Initial commit

master
Kuba Orlik 3 years ago
commit c57a3c2d1b

3
.gitignore vendored

@ -0,0 +1,3 @@
/node_modules/
/@types/
/lib/

@ -0,0 +1,14 @@
{
useTabs: true,
tabWidth: 4,
trailingComma: "es5",
"overrides": [
{
"files": "*.yml",
"options": {
"tabWidth": 2,
"useTabs": false
}
}
]
}

163
package-lock.json generated

@ -0,0 +1,163 @@
{
"name": "poznan-sm-submit",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.14.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz",
"integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ=="
},
"@types/tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
},
"async-spawner": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/async-spawner/-/async-spawner-0.1.0.tgz",
"integrity": "sha512-I/5cYWGgH5LJiHqWTwPLu7yM4XqT7dtMo77bPWtdtmOqbT9xpxF/ckasT2kdubMw8D0QD6/nSTPx+ZjvbhW/jQ==",
"requires": {
"@types/node": "^14.14.19",
"emittery": "^0.8.0"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"axios-cookiejar-support": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz",
"integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==",
"requires": {
"is-redirect": "^1.0.0",
"pify": "^5.0.0"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"emittery": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.0.tgz",
"integrity": "sha512-XMGToId3CejfmZg/0qOzdTT3WFuAN8fQYtcKXccabRfCzGiWMSTydMshHGLyx9C/ejMl4nw9tvqrn12QVFPIUg=="
},
"epsg-index": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/epsg-index/-/epsg-index-1.0.0.tgz",
"integrity": "sha512-7EcEC97QaNzSKakpc6HgVdxBc7G1vEuNRIygjVXBvrLA+t8+4QlK6jisf0g552eSzBIAkx0IRmd/CWJKLc/W5A=="
},
"follow-redirects": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
},
"form-data": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"is-redirect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
"integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
},
"mgrs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
"integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk="
},
"mime-db": {
"version": "1.45.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
"integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w=="
},
"mime-types": {
"version": "2.1.28",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
"integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"requires": {
"mime-db": "1.45.0"
}
},
"pify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz",
"integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA=="
},
"proj4": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.6.3.tgz",
"integrity": "sha512-XRqnLmHWlvi7jqKNTqaOUrVy72JEtOUrnlLki99yZUOSvcSeBaZ1I/EGnQ2LzplSbjSrebGAdikqCLeCxC/YEg==",
"requires": {
"mgrs": "1.0.0",
"wkt-parser": "^1.2.4"
}
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.1.2"
}
},
"transform-coordinates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/transform-coordinates/-/transform-coordinates-1.0.0.tgz",
"integrity": "sha512-6kZMpg+TBThUO7lbt9lWbM/DiRED+lczpjjRN3R7CB0xTEfVYqx3X9pBZx0gpihdmiUZNghArYKBiZNG4XDFYA==",
"requires": {
"epsg-index": "^1.0.0",
"proj4": "^2.4.4"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"wkt-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.4.tgz",
"integrity": "sha512-ZzKnc7ml/91fOPh5bANBL4vUlWPIYYv11waCtWTkl2TRN+LEmBg60Q1MA8gqV4hEp4MGfSj9JiHz91zw/gTDXg=="
}
}
}

@ -0,0 +1,23 @@
{
"name": "poznan-sm-submit",
"version": "0.1.0",
"description": "submit report to Poznań's Straż Miejska",
"main": "dist/index.js",
"types": "./@types/index.d.ts",
"scripts": {
"build": "tsc",
"watch": "npm run build -- --watch"
},
"author": "Kuba Orlik",
"license": "ISC",
"dependencies": {
"@types/node": "^14.14.19",
"@types/tough-cookie": "^4.0.0",
"async-spawner": "^0.1.0",
"axios": "^0.21.1",
"axios-cookiejar-support": "^1.0.1",
"form-data": "^3.0.0",
"tough-cookie": "^4.0.0",
"transform-coordinates": "^1.0.0"
}
}

@ -0,0 +1,182 @@
import { promisify } from "util";
import spawn from "async-spawner";
import FormData from "form-data";
import axios from "axios";
import tough from "tough-cookie";
import fs from "fs";
import axiosCookieJarSupport from "axios-cookiejar-support";
import * as path from "path";
import { LocationData, toCityCoordinates } from "./location";
import months from "./months";
axiosCookieJarSupport(axios);
const SM_URL =
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm";
const headers = {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
Host: "www.um.poznan.pl",
Origin: "https://www.um.poznan.pl",
Referer:
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm",
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0",
};
const minimal_data = {
lhs: "eurzad",
instance: "poznan_sm",
};
function formatTimestamp(timestamp: Date) {
const date_str = `${timestamp.getDate()} ${
months[timestamp.getMonth()]
} ${timestamp.getFullYear()}`;
const time = `${timestamp.getHours()}:${
timestamp.getMinutes() < 10 ? "0" : ""
}${timestamp.getMinutes()}`;
return [date_str, time];
}
type ContactDetails = {
email: string;
imie_nazwisko: string;
adres: string;
};
export async function submit(
location: LocationData,
reason: string,
photos: Array<string>,
timestamp: Date,
contact_details: ContactDetails
) {
if (location.address.includes("\n")) {
throw new Error("no newlines allowed in address");
}
const { x, y } = toCityCoordinates(location.coordinates);
const jar = new tough.CookieJar();
const transport = axios.create({
withCredentials: true,
});
await transport.get(SM_URL, {
headers,
jar,
});
const subject = `Nieprawidłowo zaparkowany samochód - ${location.address}`;
const [date_str, hour] = formatTimestamp(timestamp);
const body = `Samochód ${reason || ""}. Zdjęci${
photos.length === 1 ? "e" : "a"
} wykonane ${date_str} o godz. ${hour} w pobliżu ul. ${
location.address
}. Wnoszę o ukaranie.
`;
const main_data = {
...minimal_data,
srs: "EPSG:2177",
uz_process_personal_data_agreement: "Y",
uz_kategoria: 86808,
uz_temat: subject,
uz_tresc: body,
uz_email: contact_details.email,
uz_odpowiedz: "tak",
uz_imie_nazwisko: contact_details.imie_nazwisko,
uz_adres: contact_details.adres,
};
const forms = [
{
...main_data,
source: "sm_zgloszenia_step1",
goto_sm_zgloszenia_step1_1: "",
},
{
source: "sm_zgloszenia_step1_1",
x,
y,
lon: x,
lat: y,
srs: "EPSG:2177",
id_ulica_city: "Poznań",
srs_id: "EPSG:2177",
id_ulica_street_lookup: "Limanowskiego",
goto_sm_zgloszenia_step1: "",
},
{ ...main_data, goto_sm_zgloszenia_step1_2: "" },
...photos.map((file_path) => ({
...minimal_data,
source: "sm_zgloszenia_step1_2",
goto_sm_zgloszenia_step1_2: "",
uz_file: {
path: file_path,
filename: "photo1.jpg",
contentType: "image/jpeg",
},
})),
{
...minimal_data,
source: "sm_zgloszenia_step1_2",
goto_sm_zgloszenia_step1: "",
},
{ ...main_data, source: "sm_zgloszenia_step1", goto_summary: "" },
];
for (let form of forms) {
const formData = new FormData();
for (let [key, value] of Object.entries(form)) {
if (value.path) {
formData.append(key, fs.createReadStream(value.path), {
filename: value.filename,
contentType: value.contentType,
});
} else {
formData.append(key, value);
}
}
const response = await transport.post(SM_URL, formData, {
headers: { ...headers, ...formData.getHeaders() },
jar,
});
console.log(response.request._headers);
}
const session_id = (jar as any).store.idx["www.um.poznan.pl"]["/mim"]
.JSESSIONID.value;
const response = await spawn("curl", [
"https://www.um.poznan.pl/mim/forms/sm_zgloszenia.html?instance=poznan_sm",
"-H",
`User-Agent: ${headers["User-Agent"]}`,
"-H",
`Accept: ${headers.Accept}`,
"-H",
"Accept-Language: en-US,en;q=0.5",
"--compressed",
"-H",
"Content-Type: application/x-www-form-urlencoded",
"-H",
`Origin: ${headers.Origin}`,
"-H",
"DNT: 1",
"-H",
"Connection: keep-alive",
"-H",
`Referer: ${headers.Referer}`,
"-H",
`Cookie: mim_cookie_test=enabled; JSESSIONID=${session_id}`,
"-H",
"Upgrade-Insecure-Requests: 1",
"--data",
`action=save&source=summary&instance=poznan_sm&x=${x}&y=${y}&lon=${x}&lat=${y}&srs=EPSG%3A2177&goto_thanks=`,
]);
console.log(response);
}

@ -0,0 +1,26 @@
import transformation from "transform-coordinates";
export type Coordinates = {
lat: number;
lon: number;
};
export type CityCoordinates = {
x: number;
y: number;
z: number;
};
export interface LocationData {
coordinates: Coordinates;
address: string;
}
export function toCityCoordinates(coords: Coordinates): CityCoordinates {
const transform = transformation("EPSG:4326", "EPSG:2177");
const city_coordinates = transform.forward({
x: coords.lon,
y: coords.lat,
});
return city_coordinates;
}

@ -0,0 +1,16 @@
const months = [
"stycznia",
"lutego",
"marca",
"kwietnia",
"maja",
"czerwca",
"lipca",
"sierpnia",
"września",
"października",
"listopada",
"grudnia",
];
export default months;

@ -0,0 +1,11 @@
declare module "transform-coordinates" {
export default function getTransport(
coords1: string,
coords2: string
): {
forward: (coords: {
x: number;
y: number;
}) => { x: number; y: number; z: number };
};
}

@ -0,0 +1,19 @@
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node",
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"target": "ES2020",
"declaration": true,
"esModuleInterop": true,
"lib": ["es6", "esnext"],
"outDir": "lib",
"checkJs": true,
"allowJs": true,
"declarationDir": "@types",
"sourceMap": true
},
"include": ["src/**/*"]
}
Loading…
Cancel
Save