@stamhoofd/redirecter 2.39.1 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ import stamhoofdEslint from 'eslint-plugin-stamhoofd';
2
+
3
+ export default [
4
+ ...stamhoofdEslint.configs.backend,
5
+ ];
package/index.ts CHANGED
@@ -1,52 +1,55 @@
1
- require('@stamhoofd/backend-env').load({ service: "redirecter" })
2
- import { Router, RouterServer } from "@simonbackx/simple-endpoints";
3
- import { Country } from "@stamhoofd/structures";
1
+ import backendEnv from '@stamhoofd/backend-env';
2
+ backendEnv.load({ service: 'redirecter' });
4
3
 
5
- import { Geolocator } from "./src/classes/Geolocator";
4
+ import { Router, RouterServer } from '@simonbackx/simple-endpoints';
5
+ import { Country } from '@stamhoofd/structures';
6
6
 
7
- process.on("unhandledRejection", (error: Error) => {
8
- console.error("unhandledRejection");
7
+ import { Geolocator } from './src/classes/Geolocator';
8
+
9
+ process.on('unhandledRejection', (error: Error) => {
10
+ console.error('unhandledRejection');
9
11
  console.error(error.message, error.stack);
10
12
  process.exit(1);
11
13
  });
12
14
 
13
15
  // Set timezone!
14
- process.env.TZ = "UTC";
16
+ process.env.TZ = 'UTC';
15
17
 
16
18
  // Quick check
17
- if (new Date().getTimezoneOffset() != 0) {
18
- throw new Error("Process should always run in UTC timezone");
19
+ if (new Date().getTimezoneOffset() !== 0) {
20
+ throw new Error('Process should always run in UTC timezone');
19
21
  }
20
22
 
21
- const start = async () => {
22
- await Geolocator.shared.load(__dirname+"/src/data/belgium.csv", Country.Belgium)
23
+ const start = async () => {
24
+ await Geolocator.shared.load(__dirname + '/src/data/belgium.csv', Country.Belgium);
23
25
 
24
26
  // Netherlands not needed, because it is the current default
25
- //await Geolocator.shared.load(__dirname+"/src/data/netherlands.csv", Country.Netherlands)
27
+ // await Geolocator.shared.load(__dirname+"/src/data/netherlands.csv", Country.Netherlands)
26
28
 
27
- console.log("Initialising server...")
29
+ console.log('Initialising server...');
28
30
  const router = new Router();
29
- await router.loadAllEndpoints(__dirname + "/src/endpoints");
30
- await router.loadAllEndpoints(__dirname + "/src/endpoints/*");
31
+ await router.loadAllEndpoints(__dirname + '/src/endpoints');
32
+ await router.loadAllEndpoints(__dirname + '/src/endpoints/*');
31
33
 
32
34
  const routerServer = new RouterServer(router);
33
- routerServer.verbose = false
35
+ routerServer.verbose = false;
34
36
  routerServer.listen(STAMHOOFD.PORT ?? 9090);
35
37
 
36
38
  const shutdown = async () => {
37
- console.log("Shutting down...")
39
+ console.log('Shutting down...');
38
40
  // Disable keep alive
39
- routerServer.defaultHeaders = Object.assign(routerServer.defaultHeaders, { 'Connection': 'close' })
41
+ routerServer.defaultHeaders = Object.assign(routerServer.defaultHeaders, { Connection: 'close' });
40
42
  if (routerServer.server) {
41
43
  routerServer.server.headersTimeout = 5000;
42
44
  routerServer.server.keepAliveTimeout = 1;
43
45
  }
44
46
 
45
47
  try {
46
- await routerServer.close()
47
- console.log("HTTP server stopped");
48
- } catch (err) {
49
- console.error("Failed to stop HTTP server:");
48
+ await routerServer.close();
49
+ console.log('HTTP server stopped');
50
+ }
51
+ catch (err) {
52
+ console.error('Failed to stop HTTP server:');
50
53
  console.error(err);
51
54
  }
52
55
 
@@ -54,24 +57,24 @@ const start = async () => {
54
57
  process.exit(0);
55
58
  };
56
59
 
57
- process.on("SIGTERM", () => {
58
- console.info("SIGTERM signal received.");
60
+ process.on('SIGTERM', () => {
61
+ console.info('SIGTERM signal received.');
59
62
  shutdown().catch((e) => {
60
- console.error(e)
63
+ console.error(e);
61
64
  process.exit(1);
62
65
  });
63
66
  });
64
67
 
65
- process.on("SIGINT", () => {
66
- console.info("SIGINT signal received.");
68
+ process.on('SIGINT', () => {
69
+ console.info('SIGINT signal received.');
67
70
  shutdown().catch((e) => {
68
- console.error(e)
71
+ console.error(e);
69
72
  process.exit(1);
70
73
  });
71
74
  });
72
75
  };
73
76
 
74
- start().catch(error => {
75
- console.error("unhandledRejection", error);
77
+ start().catch((error) => {
78
+ console.error('unhandledRejection', error);
76
79
  process.exit(1);
77
80
  });
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@stamhoofd/redirecter",
3
- "version": "2.39.1",
3
+ "version": "2.40.0",
4
4
  "main": "index.ts",
5
5
  "license": "UNLICENCED",
6
6
  "scripts": {
7
7
  "build": "rm -rf ./dist/src/data && tsc -b && mkdir -p ./dist/src/data && cp ./src/data/* ./dist/src/data",
8
8
  "build:full": "rm -rf ./dist && yarn build",
9
9
  "start": "yarn build && node ./dist/index.js",
10
- "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
10
+ "lint": "eslint"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@types/node": "^20.12"
@@ -16,5 +16,5 @@
16
16
  "@simonbackx/simple-endpoints": "1.14.0",
17
17
  "@simonbackx/simple-logging": "^1.0.1"
18
18
  },
19
- "gitHead": "13df02459d27104c9bf92ff3d905920cf81276c4"
19
+ "gitHead": "6839689f56361c6ba6f34f6113a5cdc4bbd7b209"
20
20
  }
@@ -1,81 +1,81 @@
1
- import { Country } from "@stamhoofd/structures";
2
- import fs from "fs";
3
- import readline from "readline";
1
+ import { Country } from '@stamhoofd/structures';
2
+ import fs from 'fs';
3
+ import readline from 'readline';
4
4
 
5
5
  function fromIP(ip: string): Buffer {
6
- const splitted = ip.split(".")
7
- if (splitted.length != 4) {
8
- throw new Error("Invalid ipv4 address " + ip)
6
+ const splitted = ip.split('.');
7
+ if (splitted.length !== 4) {
8
+ throw new Error('Invalid ipv4 address ' + ip);
9
9
  }
10
10
 
11
- return Buffer.from(splitted.map(s => parseInt(s)))
11
+ return Buffer.from(splitted.map(s => parseInt(s)));
12
12
  }
13
13
 
14
14
  class IPRange {
15
- start: Buffer
16
- end: Buffer // included
15
+ start: Buffer;
16
+ end: Buffer; // included
17
17
 
18
- carrier: string
18
+ carrier: string;
19
19
 
20
20
  constructor(start: string, end: string, carrier: string) {
21
- this.start = fromIP(start)
22
- this.end = fromIP(end)
23
- this.carrier = carrier
21
+ this.start = fromIP(start);
22
+ this.end = fromIP(end);
23
+ this.carrier = carrier;
24
24
  }
25
25
 
26
26
  includes(ip: Buffer): boolean {
27
- return this.start.compare(ip) <= 0 && this.end.compare(ip) >= 0
27
+ return this.start.compare(ip) <= 0 && this.end.compare(ip) >= 0;
28
28
  }
29
29
  }
30
30
 
31
31
  export class Geolocator {
32
- static shared = new Geolocator()
32
+ static shared = new Geolocator();
33
33
 
34
- ranges: Map<Country, IPRange[]> = new Map()
34
+ ranges: Map<Country, IPRange[]> = new Map();
35
35
 
36
36
  async load(file: string, country: Country) {
37
37
  const lineReader = readline.createInterface({
38
- input: fs.createReadStream(file, { encoding: "utf-8" })
38
+ input: fs.createReadStream(file, { encoding: 'utf-8' }),
39
39
  });
40
40
 
41
- const range = this.ranges.get(country) ?? []
42
- this.ranges.set(country, range)
41
+ const range = this.ranges.get(country) ?? [];
42
+ this.ranges.set(country, range);
43
43
 
44
44
  for await (const line of lineReader) {
45
- const splitted = line.split(",")
45
+ const splitted = line.split(',');
46
46
  if (splitted.length < 2) {
47
47
  console.error(`Failed to parse line: ${line}`);
48
48
  continue;
49
49
  }
50
- const from = splitted[0]
51
- const to = splitted[1]
50
+ const from = splitted[0];
51
+ const to = splitted[1];
52
52
 
53
- console.log("From ", from, "to", to)
54
- range.push(new IPRange(from, to, splitted[4] ?? ""))
53
+ console.log('From ', from, 'to', to);
54
+ range.push(new IPRange(from, to, splitted[4] ?? ''));
55
55
  }
56
56
  }
57
57
 
58
58
  getCountry(ip: string): Country | undefined {
59
- const parsed = fromIP(ip)
59
+ const parsed = fromIP(ip);
60
60
 
61
61
  for (const [country, ranges] of this.ranges) {
62
62
  for (const range of ranges) {
63
63
  if (range.includes(parsed)) {
64
- return country
64
+ return country;
65
65
  }
66
66
  }
67
67
  }
68
68
  }
69
69
 
70
- getInfo(ip: string): { country: Country, carrier: string } | undefined {
71
- const parsed = fromIP(ip)
70
+ getInfo(ip: string): { country: Country; carrier: string } | undefined {
71
+ const parsed = fromIP(ip);
72
72
 
73
73
  for (const [country, ranges] of this.ranges) {
74
74
  for (const range of ranges) {
75
75
  if (range.includes(parsed)) {
76
- return {country, carrier: range.carrier}
76
+ return { country, carrier: range.carrier };
77
77
  }
78
78
  }
79
79
  }
80
80
  }
81
- }
81
+ }
@@ -1,58 +1,55 @@
1
- import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints'
1
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { Country } from '@stamhoofd/structures';
3
- import { URL } from "url";
4
3
 
5
4
  import { Geolocator } from '../classes/Geolocator';
6
5
 
7
6
  type Params = Record<string, never>;
8
- type Body = undefined
9
- type Query = undefined
10
- type ResponseBody = string
7
+ type Body = undefined;
8
+ type Query = undefined;
9
+ type ResponseBody = string;
11
10
 
12
11
  function getRequestIP(request: Request): string {
13
12
  let ipAddress = request.request?.socket.remoteAddress;
14
- if (request.headers["x-real-ip"] && typeof request.headers["x-real-ip"] == "string" && (ipAddress == "127.0.0.1" || ipAddress == "0.0.0.0")) {
15
- ipAddress = request.headers["x-real-ip"];
13
+ if (request.headers['x-real-ip'] && typeof request.headers['x-real-ip'] === 'string' && (ipAddress === '127.0.0.1' || ipAddress === '0.0.0.0')) {
14
+ ipAddress = request.headers['x-real-ip'];
16
15
  }
17
16
  if (!ipAddress) {
18
17
  ipAddress = '?';
19
18
  }
20
19
 
21
- return ipAddress.split(":", 2)[0]
20
+ return ipAddress.split(':', 2)[0];
22
21
  }
23
22
 
24
-
25
- export class RedirectEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
26
- protected doesMatch(request: Request): [true, Params] | [false] {
27
- return [true, {}]
23
+ export class RedirectEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
24
+ protected doesMatch(_request: Request): [true, Params] | [false] {
25
+ return [true, {}];
28
26
  }
29
27
 
30
28
  async handle(request: DecodedRequest<Params, Query, Body>) {
31
- const ip = getRequestIP(request.request)
32
-
33
- const country = Geolocator.shared.getCountry(ip)
29
+ const ip = getRequestIP(request.request);
34
30
 
35
- const path = request.request.request?.url ?? ""
31
+ const country = Geolocator.shared.getCountry(ip);
36
32
 
33
+ const path = request.request.request?.url ?? '';
37
34
 
38
35
  if (country === Country.Belgium) {
39
- const url = "https://www.stamhoofd.be"+path
40
- const response = new Response("Doorverwijzen naar "+url)
41
- response.status = 302
42
- response.headers["Location"] = url
36
+ const url = 'https://www.stamhoofd.be' + path;
37
+ const response = new Response('Doorverwijzen naar ' + url);
38
+ response.status = 302;
39
+ response.headers['Location'] = url;
43
40
 
44
41
  // Prevent encoding and version requirement
45
- response.headers["Content-Type"] = "text/html"
42
+ response.headers['Content-Type'] = 'text/html';
46
43
  return Promise.resolve(response);
47
44
  }
48
45
 
49
- const url = "https://www.stamhoofd.nl"+path
50
- const response = new Response("Doorverwijzen naar "+url)
51
- response.status = 302
52
- response.headers["Location"] = url
46
+ const url = 'https://www.stamhoofd.nl' + path;
47
+ const response = new Response('Doorverwijzen naar ' + url);
48
+ response.status = 302;
49
+ response.headers['Location'] = url;
53
50
 
54
51
  // Prevent encoding and version requirement
55
- response.headers["Content-Type"] = "text/html"
52
+ response.headers['Content-Type'] = 'text/html';
56
53
  return Promise.resolve(response);
57
54
  }
58
55
  }
package/stamhoofd.d.ts CHANGED
@@ -1,15 +1,14 @@
1
-
2
1
  export {};
3
2
 
4
3
  /**
5
- * Stamhoofd uses a global variable to store some configurations. We don't use process.env because we can only store
6
- * strings into those files. And we need objects for our localized domains (different domains for each locale).
4
+ * Stamhoofd uses a global variable to store some configurations. We don't use process.env because we can only store
5
+ * strings into those files. And we need objects for our localized domains (different domains for each locale).
7
6
  * Having to encode and decode those values would be inefficient.
8
- *
9
- * So we use our own global configuration variable: STAMHOOFD. Available everywhere and contains
10
- * other information depending on the environment (frontend/backend/shared). TypeScript will
7
+ *
8
+ * So we use our own global configuration variable: STAMHOOFD. Available everywhere and contains
9
+ * other information depending on the environment (frontend/backend/shared). TypeScript will
11
10
  * always suggest the possible keys.
12
11
  */
13
12
  declare global {
14
- const STAMHOOFD: RedirecterEnvironment
15
- }
13
+ const STAMHOOFD: RedirecterEnvironment;
14
+ }
package/.eslintrc.js DELETED
@@ -1,61 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- ignorePatterns: ["dist/", "node_modules/"],
4
- parserOptions: {
5
- "ecmaVersion": 2017
6
- },
7
- env: {
8
- "es6": true,
9
- "node": true,
10
- },
11
- extends: [
12
- "eslint:recommended",
13
- ],
14
- plugins: [],
15
- rules: {
16
- "no-console": "off",
17
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
18
- "sort-imports": "off",
19
- "import/order": "off"
20
- },
21
- overrides: [
22
- {
23
- // Rules for TypeScript and vue
24
- files: ["*.ts"],
25
- parser: "@typescript-eslint/parser",
26
- parserOptions: {
27
- project: ["./tsconfig.json"]
28
- },
29
- plugins: ["@typescript-eslint", "jest"],
30
- extends: [
31
- "eslint:recommended",
32
- "plugin:@typescript-eslint/eslint-recommended",
33
- "plugin:@typescript-eslint/recommended",
34
- "plugin:@typescript-eslint/recommended-requiring-type-checking",
35
- "plugin:jest/recommended",
36
- ],
37
- rules: {
38
- "no-console": "off",
39
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
40
- "sort-imports": "off",
41
- "import/order": "off",
42
- "@typescript-eslint/explicit-function-return-type": "off",
43
- "@typescript-eslint/no-explicit-any": "off",
44
- "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
45
- "@typescript-eslint/no-namespace": "off",
46
- "@typescript-eslint/no-floating-promises": "error",
47
- "@typescript-eslint/no-misused-promises": "error",
48
- "@typescript-eslint/prefer-for-of": "warn",
49
- "@typescript-eslint/no-empty-interface": "off", // It is convenient to have placeholder interfaces
50
- "@typescript-eslint/no-this-alias": "off", // No idea why we need this. This breaks code that is just fine. Prohibit the use of function() instead of this rule
51
- "@typescript-eslint/unbound-method": "off", // Methods are automatically bound in vue, it would break removeEventListeners if we bound it every time unless we save every method in variables again...
52
- "@typescript-eslint/no-unsafe-assignment": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
53
- "@typescript-eslint/no-unsafe-return": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
54
- "@typescript-eslint/no-unsafe-call": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
55
- "@typescript-eslint/no-unsafe-member-access": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
56
- "@typescript-eslint/restrict-plus-operands": "off", // bullshit one
57
- "@typescript-eslint/explicit-module-boundary-types": "off",
58
- },
59
- }
60
- ]
61
- };