summary refs log tree commit diff
path: root/src/api/util
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2022-09-17 23:35:31 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2022-09-17 23:35:31 +0200
commit258b96757f2d30f68ce873be04b5169de1e1eb9b (patch)
tree97cd6fe041c820d7d61a419b1b424af109e85aee /src/api/util
parentPartially refactor code to use localization (diff)
downloadserver-258b96757f2d30f68ce873be04b5169de1e1eb9b.tar.xz
Cryptographically secure invites, add generation of tokens
Diffstat (limited to 'src/api/util')
-rw-r--r--src/api/util/handlers/Voice.ts3
-rw-r--r--src/api/util/index.ts8
-rw-r--r--src/api/util/utility/Base64.ts47
-rw-r--r--src/api/util/utility/RandomInviteID.ts31
-rw-r--r--src/api/util/utility/String.ts18
-rw-r--r--src/api/util/utility/captcha.ts47
-rw-r--r--src/api/util/utility/ipAddress.ts99
-rw-r--r--src/api/util/utility/passwordStrength.ts59
8 files changed, 2 insertions, 310 deletions
diff --git a/src/api/util/handlers/Voice.ts b/src/api/util/handlers/Voice.ts
index 4d60eb91..98d28ff0 100644
--- a/src/api/util/handlers/Voice.ts
+++ b/src/api/util/handlers/Voice.ts
@@ -1,5 +1,4 @@
-import { Config } from "@fosscord/util";
-import { distanceBetweenLocations, IPAnalysis } from "../utility/ipAddress";
+import { Config, distanceBetweenLocations, IPAnalysis } from "@fosscord/util";
 
 export async function getVoiceRegions(ipAddress: string, vip: boolean) {
 	const regions = Config.get().regions;
diff --git a/src/api/util/index.ts b/src/api/util/index.ts
index d06860cd..7223d6f4 100644
--- a/src/api/util/index.ts
+++ b/src/api/util/index.ts
@@ -1,10 +1,4 @@
 export * from "./entities/AssetCacheItem";
 export * from "./handlers/Message";
 export * from "./handlers/route";
-export * from "./handlers/Voice";
-export * from "./utility/Base64";
-export * from "./utility/captcha";
-export * from "./utility/ipAddress";
-export * from "./utility/passwordStrength";
-export * from "./utility/RandomInviteID";
-export * from "./utility/String";
+export * from "./handlers/Voice";
\ No newline at end of file
diff --git a/src/api/util/utility/Base64.ts b/src/api/util/utility/Base64.ts
deleted file mode 100644
index 46cff77a..00000000
--- a/src/api/util/utility/Base64.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
-
-// binary to string lookup table
-const b2s = alphabet.split("");
-
-// string to binary lookup table
-// 123 == 'z'.charCodeAt(0) + 1
-const s2b = new Array(123);
-for (let i = 0; i < alphabet.length; i++) {
-	s2b[alphabet.charCodeAt(i)] = i;
-}
-
-// number to base64
-export const ntob = (n: number): string => {
-	if (n < 0) return `-${ntob(-n)}`;
-
-	let lo = n >>> 0;
-	let hi = (n / 4294967296) >>> 0;
-
-	let right = "";
-	while (hi > 0) {
-		right = b2s[0x3f & lo] + right;
-		lo >>>= 6;
-		lo |= (0x3f & hi) << 26;
-		hi >>>= 6;
-	}
-
-	let left = "";
-	do {
-		left = b2s[0x3f & lo] + left;
-		lo >>>= 6;
-	} while (lo > 0);
-
-	return left + right;
-};
-
-// base64 to number
-export const bton = (base64: string) => {
-	let number = 0;
-	const sign = base64.charAt(0) === "-" ? 1 : 0;
-
-	for (let i = sign; i < base64.length; i++) {
-		number = number * 64 + s2b[base64.charCodeAt(i)];
-	}
-
-	return sign ? -number : number;
-};
diff --git a/src/api/util/utility/RandomInviteID.ts b/src/api/util/utility/RandomInviteID.ts
deleted file mode 100644
index feebfd3d..00000000
--- a/src/api/util/utility/RandomInviteID.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Snowflake } from "@fosscord/util";
-
-export function random(length = 6) {
-	// Declare all characters
-	let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-
-	// Pick characers randomly
-	let str = "";
-	for (let i = 0; i < length; i++) {
-		str += chars.charAt(Math.floor(Math.random() * chars.length));
-	}
-
-	return str;
-}
-
-export function snowflakeBasedInvite() {
-	// Declare all characters
-	let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-	let base = BigInt(chars.length);
-	let snowflake = Snowflake.generateWorkerProcess();
-
-	// snowflakes hold ~10.75 characters worth of entropy;
-	// safe to generate a 8-char invite out of them
-	let str = "";
-	for (let i = 0; i < 10; i++) {
-		str.concat(chars.charAt(Number(snowflake % base)));
-		snowflake = snowflake / base;
-	}
-
-	return str.substr(3, 8).split("").reverse().join("");
-}
diff --git a/src/api/util/utility/String.ts b/src/api/util/utility/String.ts
deleted file mode 100644
index a2e491e4..00000000
--- a/src/api/util/utility/String.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { FieldErrors } from "@fosscord/util";
-import { Request } from "express";
-import { ntob } from "./Base64";
-
-export function checkLength(str: string, min: number, max: number, key: string, req: Request) {
-	if (str.length < min || str.length > max) {
-		throw FieldErrors({
-			[key]: {
-				code: "BASE_TYPE_BAD_LENGTH",
-				message: req.t("common:field.BASE_TYPE_BAD_LENGTH", { length: `${min} - ${max}` })
-			}
-		});
-	}
-}
-
-export function generateCode() {
-	return ntob(Date.now() + Math.randomIntBetween(0, 10000));
-}
diff --git a/src/api/util/utility/captcha.ts b/src/api/util/utility/captcha.ts
deleted file mode 100644
index 02983f3f..00000000
--- a/src/api/util/utility/captcha.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Config } from "@fosscord/util";
-import fetch from "node-fetch";
-
-export interface hcaptchaResponse {
-	success: boolean;
-	challenge_ts: string;
-	hostname: string;
-	credit: boolean;
-	"error-codes": string[];
-	score: number; // enterprise only
-	score_reason: string[]; // enterprise only
-}
-
-export interface recaptchaResponse {
-	success: boolean;
-	score: number; // between 0 - 1
-	action: string;
-	challenge_ts: string;
-	hostname: string;
-	"error-codes"?: string[];
-}
-
-const verifyEndpoints = {
-	hcaptcha: "https://hcaptcha.com/siteverify",
-	recaptcha: "https://www.google.com/recaptcha/api/siteverify"
-};
-
-export async function verifyCaptcha(response: string, ip?: string) {
-	const { security } = Config.get();
-	const { service, secret, sitekey } = security.captcha;
-
-	if (!service) throw new Error("Cannot verify captcha without service");
-
-	const res = await fetch(verifyEndpoints[service], {
-		method: "POST",
-		headers: {
-			"Content-Type": "application/x-www-form-urlencoded"
-		},
-		body:
-			`response=${encodeURIComponent(response)}` +
-			`&secret=${encodeURIComponent(secret!)}` +
-			`&sitekey=${encodeURIComponent(sitekey!)}` +
-			(ip ? `&remoteip=${encodeURIComponent(ip!)}` : "")
-	});
-
-	return (await res.json()) as hcaptchaResponse | recaptchaResponse;
-}
diff --git a/src/api/util/utility/ipAddress.ts b/src/api/util/utility/ipAddress.ts
deleted file mode 100644
index c96feb9e..00000000
--- a/src/api/util/utility/ipAddress.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import { Config } from "@fosscord/util";
-import { Request } from "express";
-// use ipdata package instead of simple fetch because of integrated caching
-import fetch from "node-fetch";
-
-const exampleData = {
-	ip: "",
-	is_eu: true,
-	city: "",
-	region: "",
-	region_code: "",
-	country_name: "",
-	country_code: "",
-	continent_name: "",
-	continent_code: "",
-	latitude: 0,
-	longitude: 0,
-	postal: "",
-	calling_code: "",
-	flag: "",
-	emoji_flag: "",
-	emoji_unicode: "",
-	asn: {
-		asn: "",
-		name: "",
-		domain: "",
-		route: "",
-		type: "isp"
-	},
-	languages: [
-		{
-			name: "",
-			native: ""
-		}
-	],
-	currency: {
-		name: "",
-		code: "",
-		symbol: "",
-		native: "",
-		plural: ""
-	},
-	time_zone: {
-		name: "",
-		abbr: "",
-		offset: "",
-		is_dst: true,
-		current_time: ""
-	},
-	threat: {
-		is_tor: false,
-		is_proxy: false,
-		is_anonymous: false,
-		is_known_attacker: false,
-		is_known_abuser: false,
-		is_threat: false,
-		is_bogon: false
-	},
-	count: 0,
-	status: 200
-};
-
-//TODO add function that support both ip and domain names
-export async function IPAnalysis(ip: string): Promise<typeof exampleData> {
-	const { ipdataApiKey } = Config.get().security;
-	if (!ipdataApiKey) return { ...exampleData, ip };
-
-	return (await fetch(`https://api.ipdata.co/${ip}?api-key=${ipdataApiKey}`)).json() as any;
-}
-
-export function isProxy(data: typeof exampleData) {
-	if (!data || !data.asn || !data.threat) return false;
-	if (data.asn.type !== "isp") return true;
-	if (Object.values(data.threat).some((x) => x)) return true;
-
-	return false;
-}
-
-export function getIpAdress(req: Request): string {
-	// @ts-ignore
-	return (
-		req.headers[Config.get().security.forwadedFor as string] ||
-		req.headers[Config.get().security.forwadedFor?.toLowerCase() as string] ||
-		req.socket.remoteAddress
-	);
-}
-
-export function distanceBetweenLocations(loc1: any, loc2: any): number {
-	return distanceBetweenCoords(loc1.latitude, loc1.longitude, loc2.latitude, loc2.longitude);
-}
-
-//Haversine function
-function distanceBetweenCoords(lat1: number, lon1: number, lat2: number, lon2: number) {
-	const p = 0.017453292519943295; // Math.PI / 180
-	const c = Math.cos;
-	const a = 0.5 - c((lat2 - lat1) * p) / 2 + (c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p))) / 2;
-
-	return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
-}
diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts
deleted file mode 100644
index ff83d3df..00000000
--- a/src/api/util/utility/passwordStrength.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { Config } from "@fosscord/util";
-
-const reNUMBER = /[0-9]/g;
-const reUPPERCASELETTER = /[A-Z]/g;
-const reSYMBOLS = /[A-Z,a-z,0-9]/g;
-
-const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db
-/*
- * https://en.wikipedia.org/wiki/Password_policy
- * password must meet following criteria, to be perfect:
- *  - min <n> chars
- *  - min <n> numbers
- *  - min <n> symbols
- *  - min <n> uppercase chars
- *  - shannon entropy folded into [0, 1) interval
- *
- * Returns: 0 > pw > 1
- */
-export function checkPassword(password: string): number {
-	const { minLength, minNumbers, minUpperCase, minSymbols } = Config.get().register.password;
-	let strength = 0;
-
-	// checks for total password len
-	if (password.length >= minLength - 1) {
-		strength += 0.05;
-	}
-
-	// checks for amount of Numbers
-	if (password.count(reNUMBER) >= minNumbers - 1) {
-		strength += 0.05;
-	}
-
-	// checks for amount of Uppercase Letters
-	if (password.count(reUPPERCASELETTER) >= minUpperCase - 1) {
-		strength += 0.05;
-	}
-
-	// checks for amount of symbols
-	if (password.replace(reSYMBOLS, "").length >= minSymbols - 1) {
-		strength += 0.05;
-	}
-
-	// checks if password only consists of numbers or only consists of chars
-	if (password.length == password.count(reNUMBER) || password.length === password.count(reUPPERCASELETTER)) {
-		strength = 0;
-	}
-
-	let entropyMap: { [key: string]: number } = {};
-	for (let i = 0; i < password.length; i++) {
-		if (entropyMap[password[i]]) entropyMap[password[i]]++;
-		else entropyMap[password[i]] = 1;
-	}
-
-	let entropies = Object.values(entropyMap);
-
-	entropies.map((x) => x / entropyMap.length);
-	strength += entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / Math.log2(password.length);
-	return strength;
-}