Merge remote-tracking branch 'upstream/staging' into feat/captchaVerify

This commit is contained in:
Madeline committed 2022-08-22 22:18:59 +10:00
commit 0cd9a46eea
671 files changed
+20439 -20179

No files matched your search

View File
File renamed without changes.
+8
View File
@@ -13,3 +13,11 @@ api/assets/plugins/*.js
.idea/
*.code-workspace
*.log
*.log.ansi
bundle/depclean.*
*.tmp
tmp/
assets/cache/
+1 -2
View File
@@ -2,6 +2,5 @@
"tabWidth": 4,
"useTabs": true,
"printWidth": 140,
"trailingComma": "none",
"useTabs": true
"trailingComma": "none"
}
+17
View File
@@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${file}",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}
-8
View File
@@ -1,8 +0,0 @@
MONGO_URL=mongodb://localhost/fosscord
PORT=3001
PRODUCTION=TRUE
THREADS=# automatically use all available cores, only available if production = true
#LOG_REQUESTS=
# only log 200 and 204: LOG_REQUESTS=200 204
# log everything except 200 and 204: LOG_REQUESTS=-200 204
# log all requests: LOG_REQUESTS=-
-115
View File
@@ -1,115 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
build
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
.DS_STORE
src/ready.json
# Docker
.docker/config/*
!.docker/config/.keep
# fosscord
*.db
-1
View File
@@ -1 +0,0 @@
!dist/
-6
View File
@@ -1,6 +0,0 @@
{
"tabWidth": 4,
"useTabs": true,
"printWidth": 140,
"trailingComma": "none"
}
-25
View File
@@ -1,25 +0,0 @@
{
"API Router": {
"scope": "javascript,typescript",
"prefix": "router",
"body": [
"import { Router, Response, Request } from \"express\";",
"import { route } from \"@fosscord/api\";",
"",
"const router = Router();",
"",
"router.get(\"/\", route({}), (req: Request, res: Response) => {",
"\tres.json({});",
"});",
"",
"export default router;"
],
"description": "A basic API router setup for a blank route."
},
"Route": {
"scope": "typescript",
"prefix": "route",
"body": ["router.get(\"$1\", route({}), (req: Request, res: Response) => {", "\t$2", "});"],
"description": "An API endpoint"
}
}
-28
View File
@@ -1,28 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"sourceMaps": true,
"type": "node",
"request": "launch",
"name": "Launch Server",
"program": "${workspaceFolder}/dist/start.js",
"preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"envFile": "${workspaceFolder}/.env"
},
{
"name": "Debug current file",
"program": "${file}",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"preLaunchTask": "tsc: build - tsconfig.json",
"type": "node",
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"]
}
]
}
-12
View File
@@ -1,12 +0,0 @@
FROM node:lts-alpine
# needed for native packages (bcrypt, canvas)
RUN apk add --no-cache make gcc g++ python cairo-dev jpeg-dev pango-dev giflib-dev
WORKDIR /usr/src/fosscord-server
COPY package.json .
COPY package-lock.json .
RUN npm rebuild bcrypt --build-from-source && npm install canvas --build-from-source
RUN npm install
COPY . .
EXPOSE 3001
RUN npm run build-docker
CMD ["node", "dist/start.js"]
-67
View File
@@ -1,67 +0,0 @@
<p align="center">
<img width="100" src="https://raw.githubusercontent.com/fosscord/fosscord/master/assets/logo_big_transparent.png" />
</p>
<h1 align="center">Fosscord HTTP API Server</h1>
<p>
<a href="https://discord.gg/ZrnGQP6p3d">
<img src="https://img.shields.io/discord/806142446094385153?color=7489d5&logo=discord&logoColor=ffffff" />
</a>
<img src="https://img.shields.io/static/v1?label=Status&message=Development&color=blue">
<a title="Crowdin" target="_blank" href="https://translate.fosscord.com/"><img src="https://badges.crowdin.net/fosscord/localized.svg"></a>
<a href="https://opencollective.com/fosscord">
<img src="https://opencollective.com/fosscord/tiers/badge.svg">
</a>
</p>
## [About](https://github.com/fosscord/fosscord-server/wiki)
This repository contains the Fosscord HTTP API Server
## Bug Tracker
[Project Board](https://fosscord.notion.site/2c7fe9e73f9842d3bab3a4912dedd091)
## API
We use [express](https://expressjs.com/) for the HTTP Server and
[lambert-server](https://www.npmjs.com/package/lambert-server) for route handling and body validation (customized).
## Contribution
You should be familiar with:
- [Git](https://git-scm.com/)
- [NodeJS](https://nodejs.org/)
- [TypeScript](https://www.typescriptlang.org/)
- [MongoDB/mongoose](http://mongoosejs.com/)
and the other technologies we use
### Getting Started
Clone the Repository:
```bash
git clone https://github.com/fosscord/fosscord-server
cd fosscord-server
```
#### Install (dev)dependencies:
```bash
npm install
npm install --only=dev
```
#### Starting:
```
npm start
```
#### Debugging:
**Vscode:**
The Launch file configuration is in `./vscode/launch.json`,
so you can just debug the server by pressing `F5` or the `> Launch Server` button
File diff suppressed because it is too large. Load diff
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
["@babel/preset-typescript", { allowDeclareFields: true }]
]
};
-42
View File
@@ -1,42 +0,0 @@
<!DOCTYPE html>
<html class="theme-dark" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
<title>Discord Test Client Developer Portal</title>
<meta charset="utf-8" data-react-helmet="true" />
</head>
<body>
<div id="app-mount"></div>
<script>
window.GLOBAL_ENV = {
API_VERSION: 9,
API_ENDPOINT: "/api",
WEBAPP_ENDPOINT: "",
CDN_HOST: `${location.hostname}:3003`,
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
MARKETING_ENDPOINT: "//discord.com",
RELEASE_CHANNEL: "stable",
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
};
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
const localStorage = window.localStorage;
// TODO: remote auth
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
localStorage.setItem(
"DeveloperOptionsStore",
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
);
</script>
<script src="/assets/41fde19fdf180f3d4315.js" integrity=""></script>
<script src="/assets/7b04a3ab10e05dd9054e.js" integrity=""></script>
<script src="/assets/d1f811da193e5648048b.js" integrity=""></script>
</body>
</html>
-81
View File
@@ -1,81 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Discord Test Client</title>
<link rel="stylesheet" href="/assets/fosscord.css" />
<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
<link id="customcss" rel="stylesheet" href="/assets/user.css" />
<!-- inline plugin marker -->
<!-- preload plugin marker -->
</head>
<body>
<div id="app-mount"></div>
<script>
window.__OVERLAY__ = /overlay/.test(location.pathname);
window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
window.GLOBAL_ENV = {
API_ENDPOINT: "/api",
API_VERSION: 9,
GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.hostname}:3002`,
WEBAPP_ENDPOINT: "",
CDN_HOST: `${location.hostname}:3003`,
ASSET_ENDPOINT: "",
MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
WIDGET_ENDPOINT: `//${location.host}/widget`,
INVITE_HOST: `${location.hostname}/invite`,
GUILD_TEMPLATE_HOST: "${location.host}",
GIFT_CODE_HOST: "${location.hostname}",
RELEASE_CHANNEL: "stable",
MARKETING_ENDPOINT: "//discord.com",
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
NETWORKING_ENDPOINT: "//router.discordapp.net",
RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
PROJECT_ENV: "production",
REMOTE_AUTH_ENDPOINT: "//localhost:3020",
SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
HTML_TIMESTAMP: Date.now(),
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
};
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
const localStorage = window.localStorage;
// TODO: remote auth
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
localStorage.setItem(
"DeveloperOptionsStore",
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
);
setInterval(() => {
var token = JSON.parse(localStorage.getItem("token"));
if (token) {
var logincss = document.querySelector('#logincss'),
canRemove = logincss ? logincss: "";
if(canRemove !== "") {
document.querySelector("#logincss").remove();
canRemove = "";
}
}
}, 1000)
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
if (settings && settings.locale.length <= 2) {
// fix client locale wrong and client not loading at all
settings.locale = "en-US";
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
}
</script>
<script src="/assets/checkLocale.js"></script>
<script src="/assets/1e18f2aac02e172db283.js"></script>
<script src="/assets/681e53cdfefa5b82249a.js"></script>
<script src="/assets/7a036838c0a0e73f59d8.js"></script>
<script src="/assets/b6cf2184a7a05e7525ce.js"></script>
<!-- plugin marker -->
</body>
</html>
-66
View File
@@ -1,66 +0,0 @@
const { traverseDirectory } = require("lambert-server");
const path = require("path");
const express = require("express");
const RouteUtility = require("../dist/util/route");
const Router = express.Router;
/**
* Some documentation.
*
* @type {Map<string, RouteUtility.RouteOptions>}
*/
const routes = new Map();
let currentPath = "";
let currentFile = "";
const methods = ["get", "post", "put", "delete", "patch"];
function registerPath(file, method, prefix, path, ...args) {
const urlPath = prefix + path;
const sourceFile = file.replace("/dist/", "/src/").replace(".js", ".ts");
const opts = args.find((x) => typeof x === "object");
if (opts) {
routes.set(urlPath + "|" + method, opts); // @ts-ignore
opts.file = sourceFile;
// console.log(method, urlPath, opts);
} else {
console.log(`${sourceFile}\nrouter.${method}("${path}") is missing the "route()" description middleware\n`);
}
}
function routeOptions(opts) {
return opts;
}
// @ts-ignore
RouteUtility.route = routeOptions;
express.Router = (opts) => {
const path = currentPath;
const file = currentFile;
const router = Router(opts);
for (const method of methods) {
router[method] = registerPath.bind(null, file, method, path);
}
return router;
};
module.exports = function getRouteDescriptions() {
const root = path.join(__dirname, "..", "dist", "routes", "/");
traverseDirectory({ dirname: root, recursive: true }, (file) => {
currentFile = file;
let path = file.replace(root.slice(0, -1), "");
path = path.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
path = path.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
if (path.endsWith("/index")) path = path.slice(0, "/index".length * -1); // delete index from path
currentPath = path;
try {
require(file);
} catch (error) {
console.error("error loading file " + file, error);
}
});
return routes;
};
-20
View File
@@ -1,20 +0,0 @@
const { Config, initDatabase } = require("@fosscord/util");
const fs = require("fs");
const path = require("path");
const { FosscordServer } = require("../dist/Server");
const Server = new FosscordServer({ port: 3001 });
global.server = Server;
module.exports = async () => {
try {
fs.unlinkSync(path.join(process.cwd(), "database.db"));
} catch {}
await initDatabase();
await Config.init();
Config.get().limits.rate.disabled = true;
return await Server.start();
};
// afterAll(async () => {
// return await Server.stop();
// });
-2
View File
@@ -1,2 +0,0 @@
jest.spyOn(global.console, "log").mockImplementation(() => jest.fn());
jest.spyOn(global.console, "info").mockImplementation(() => jest.fn());
-18
View File
@@ -1,18 +0,0 @@
{
"field": {
"BASE_TYPE_REQUIRED": "Это поле является обязательным",
"BASE_TYPE_STRING": "This field must be a string",
"BASE_TYPE_NUMBER": "This field must be a number",
"BASE_TYPE_BIGINT": "This field must be a bigint",
"BASE_TYPE_BOOLEAN": "This field must be a boolean",
"BASE_TYPE_CHOICES": "Это поле должно быть одним из ({{types}})",
"BASE_TYPE_CLASS": "Это поле должно быть экземпляром {{type}}",
"BASE_TYPE_OBJECT": "This field must be an object",
"BASE_TYPE_ARRAY": "This field must be an array",
"UNKOWN_FIELD": "Unknown key: {{key}}",
"BASE_TYPE_CONSTANT": "Это поле должно быть {{value}}",
"EMAIL_TYPE_INVALID_EMAIL": "Неправильный формат адреса электронной почты",
"DATE_TYPE_PARSE": "Could not parse {{date}}. Should be ISO8601",
"BASE_TYPE_BAD_LENGTH": "Длина должна быть между {{length}} в длину"
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"login": {
"INVALID_LOGIN": "E-Mail or Phone not found",
"INVALID_PASSWORD": "Invalid Password",
"ACCOUNT_DISABLED": "This account is disabled",
"INVALID_TOTP_CODE": "Invalid two-factor code.",
"INVALID_TOTP_SECRET": "Invalid two-factor secret."
},
"register": {
"REGISTRATION_DISABLED": "New user registration is disabled",
"INVITE_ONLY": "You must be invited to register",
"EMAIL_INVALID": "Invalid Email",
"EMAIL_ALREADY_REGISTERED": "Email is already registered",
"DATE_OF_BIRTH_UNDERAGE": "You need to be {{years}} years or older",
"CONSENT_REQUIRED": "You must agree to the Terms of Service and Privacy Policy.",
"USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another"
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"field": {
"BASE_TYPE_REQUIRED": "This field is required",
"BASE_TYPE_STRING": "This field must be a string",
"BASE_TYPE_NUMBER": "This field must be a number",
"BASE_TYPE_BIGINT": "This field must be a bigint",
"BASE_TYPE_BOOLEAN": "This field must be a boolean",
"BASE_TYPE_CHOICES": "This field must be one of ({{types}})",
"BASE_TYPE_CLASS": "This field must be an instance of {{type}}",
"BASE_TYPE_OBJECT": "This field must be an object",
"BASE_TYPE_ARRAY": "This field must be an array",
"UNKOWN_FIELD": "Unknown key: {{key}}",
"BASE_TYPE_CONSTANT": "This field must be {{value}}",
"EMAIL_TYPE_INVALID_EMAIL": "Not a well-formed email address",
"DATE_TYPE_PARSE": "Could not parse {{date}}. Should be ISO8601",
"BASE_TYPE_BAD_LENGTH": "Must be between {{length}} in length"
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"login": {
"INVALID_LOGIN": "E-Mail or Phone not found",
"INVALID_PASSWORD": "Invalid Password",
"ACCOUNT_DISABLED": "This account is disabled",
"INVALID_TOTP_CODE": "Invalid two-factor code.",
"INVALID_TOTP_SECRET": "Invalid two-factor secret."
},
"register": {
"REGISTRATION_DISABLED": "New user registration is disabled",
"INVITE_ONLY": "You must be invited to register",
"EMAIL_INVALID": "Invalid Email",
"EMAIL_ALREADY_REGISTERED": "Email is already registered",
"DATE_OF_BIRTH_UNDERAGE": "You need to be {{years}} years or older",
"CONSENT_REQUIRED": "You must agree to the Terms of Service and Privacy Policy.",
"USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another"
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"login": {
"INVALID_LOGIN": "E-Mail or Phone not found",
"INVALID_PASSWORD": "Invalid Password",
"ACCOUNT_DISABLED": "This account is disabled",
"INVALID_TOTP_CODE": "Invalid two-factor code.",
"INVALID_TOTP_SECRET": "Invalid two-factor secret."
},
"register": {
"REGISTRATION_DISABLED": "New user registration is disabled",
"INVITE_ONLY": "You must be invited to register",
"EMAIL_INVALID": "Invalid Email",
"EMAIL_ALREADY_REGISTERED": "Email is already registered",
"DATE_OF_BIRTH_UNDERAGE": "You need to be {{years}} years or older",
"CONSENT_REQUIRED": "You must agree to the Terms of Service and Privacy Policy.",
"USERNAME_TOO_MANY_USERS": "Too many users have this username, please try another"
}
}
-18
View File
@@ -1,18 +0,0 @@
{
"field": {
"BASE_TYPE_REQUIRED": "This field is required",
"BASE_TYPE_STRING": "This field must be a string",
"BASE_TYPE_NUMBER": "This field must be a number",
"BASE_TYPE_BIGINT": "This field must be a bigint",
"BASE_TYPE_BOOLEAN": "This field must be a boolean",
"BASE_TYPE_CHOICES": "This field must be one of ({{types}})",
"BASE_TYPE_CLASS": "This field must be an instance of {{type}}",
"BASE_TYPE_OBJECT": "This field must be an object",
"BASE_TYPE_ARRAY": "This field must be an array",
"UNKOWN_FIELD": "Unknown key: {{key}}",
"BASE_TYPE_CONSTANT": "This field must be {{value}}",
"EMAIL_TYPE_INVALID_EMAIL": "Not a well-formed email address",
"DATE_TYPE_PARSE": "Could not parse {{date}}. Should be ISO8601",
"BASE_TYPE_BAD_LENGTH": "Must be between {{length}} in length"
}
}
BIN
View File
Binary file not shown.
-107
View File
@@ -1,107 +0,0 @@
{
"name": "@fosscord/api",
"version": "1.0.0",
"description": "This repository contains the HTTP API Server",
"main": "dist/index.js",
"types": "src/index.ts",
"scripts": {
"test:only": "npx jest --coverage --verbose --forceExit ./tests",
"test:routes": "npx jest --coverage --verbose --forceExit ./routes.test.ts",
"test": "npm run build && npm run test:only",
"test:watch": "npx jest --watch",
"start": "npm run build && node dist/start",
"build": "npx tsc -p .",
"dev": "npx tsnd --respawn src/start.ts",
"patch": "npx ts-patch install -s && npx patch-package",
"postinstall": "npm run patch",
"generate:docs": "node scripts/generate_openapi",
"generate:schema": "node scripts/generate_schema"
},
"repository": {
"type": "git",
"url": "git+https://github.com/fosscord/fosscord-server.git"
},
"keywords": [
"discord",
"fosscord",
"fosscord-server",
"fosscord-api",
"discord open source",
"discord-open-source"
],
"author": "Fosscord",
"license": "AGPL-3.0-only",
"bugs": {
"url": "https://github.com/fosscord/fosscord-server/issues"
},
"homepage": "https://fosscord.com",
"devDependencies": {
"@babel/core": "^7.15.5",
"@babel/preset-env": "^7.15.8",
"@babel/preset-typescript": "^7.15.0",
"@types/amqplib": "^0.8.1",
"@types/bcrypt": "^5.0.0",
"@types/express": "^4.17.9",
"@types/i18next-node-fs-backend": "^2.1.0",
"@types/jest": "^27.0.1",
"@types/jest-expect-message": "^1.0.3",
"@types/jsonwebtoken": "^8.5.0",
"@types/morgan": "^1.9.3",
"@types/multer": "^1.4.5",
"@types/node": "^14.18.22",
"@types/node-fetch": "^2.5.5",
"@types/supertest": "^2.0.11",
"@zerollup/ts-transform-paths": "^1.7.18",
"jest": "^27.2.5",
"jest-expect-message": "^1.0.2",
"jest-runtime": "^27.2.1",
"ts-node": "^9.1.1",
"ts-node-dev": "^1.1.6",
"ts-patch": "^1.4.4",
"typescript": "^4.4.2",
"typescript-json-schema": "0.50.1"
},
"dependencies": {
"@babel/preset-env": "^7.15.8",
"@babel/preset-typescript": "^7.15.0",
"@fosscord/util": "file:../util",
"@sentry/node": "^6.16.1",
"@sentry/tracing": "^6.16.1",
"ajv": "8.6.2",
"ajv-formats": "^2.1.1",
"amqplib": "^0.8.0",
"assert": "^1.5.0",
"bcrypt": "^5.0.1",
"body-parser": "^1.19.0",
"cheerio": "^1.0.0-rc.10",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"form-data": "^3.0.0",
"i18next": "^19.9.2",
"i18next-http-middleware": "^3.1.3",
"i18next-node-fs-backend": "^2.1.3",
"image-size": "^1.0.0",
"jsonwebtoken": "^8.5.1",
"lambert-server": "^1.2.12",
"missing-native-js-functions": "^1.2.18",
"morgan": "^1.10.0",
"multer": "^1.4.2",
"node-2fa": "^2.0.3",
"node-fetch": "^2.6.2",
"patch-package": "^6.4.7",
"picocolors": "^1.0.0",
"proxy-agent": "^5.0.0",
"supertest": "^6.1.6",
"typeorm": "^0.2.37"
},
"jest": {
"setupFiles": [
"<rootDir>/jest/setup.js"
],
"setupFilesAfterEnv": [
"jest-expect-message"
],
"globalSetup": "<rootDir>/jest/globalSetup.js",
"verbose": true
}
}
@@ -1,84 +0,0 @@
import { HTTPError } from "lambert-server";
import { route } from "@fosscord/api";
import { isTextChannel } from "./messages";
import { FindManyOptions, Between, Not } from "typeorm";
import {
Attachment,
Channel,
Config,
Embed,
DiscordApiErrors,
emitEvent,
FosscordApiErrors,
getPermission,
getRights,
Message,
MessageDeleteBulkEvent,
Snowflake,
uploadFile
} from "@fosscord/util";
import { Router, Response, Request } from "express";
import multer from "multer";
import { handleMessage, postHandleMessage } from "@fosscord/api";
const router: Router = Router();
export default router;
export interface PurgeSchema {
before: string;
after: string
}
/**
TODO: apply the delete bit by bit to prevent client and database stress
**/
router.post("/", route({ /*body: "PurgeSchema",*/ }), async (req: Request, res: Response) => {
const { channel_id } = req.params;
const channel = await Channel.findOneOrFail({ id: channel_id });
if (!channel.guild_id) throw new HTTPError("Can't purge dm channels", 400);
isTextChannel(channel.type);
const rights = await getRights(req.user_id);
if (!rights.has("MANAGE_MESSAGES")) {
const permissions = await getPermission(req.user_id, channel.guild_id, channel_id);
permissions.hasThrow("MANAGE_MESSAGES");
permissions.hasThrow("MANAGE_CHANNELS");
}
const { before, after } = req.body as PurgeSchema;
// TODO: send the deletion event bite-by-bite to prevent client stress
var query: FindManyOptions<Message> & { where: { id?: any; }; } = {
order: { id: "ASC" },
// take: limit,
where: {
channel_id,
id: Between(after, before), // the right way around
author_id: rights.has("SELF_DELETE_MESSAGES") ? undefined : Not(req.user_id)
// if you lack the right of self-deletion, you can't delete your own messages, even in purges
},
relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"]
};
const messages = await Message.find(query);
const endpoint = Config.get().cdn.endpointPublic;
if (messages.length == 0) {
res.sendStatus(304);
return;
}
await Message.delete(messages.map((x) => ({ id: x })));
await emitEvent({
event: "MESSAGE_DELETE_BULK",
channel_id,
data: { ids: messages.map(x => x.id), channel_id, guild_id: channel.guild_id }
} as MessageDeleteBulkEvent);
res.sendStatus(204);
});
-34
View File
@@ -1,34 +0,0 @@
import { Guild, Config } from "@fosscord/util";
import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
const router = Router();
router.get("/", route({}), async (req: Request, res: Response) => {
const { offset, limit, categories } = req.query;
var showAllGuilds = Config.get().guild.discovery.showAllGuilds;
var configLimit = Config.get().guild.discovery.limit;
// ! this only works using SQL querys
// TODO: implement this with default typeorm query
// const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) });
let guilds;
if (categories == undefined) {
guilds = showAllGuilds
? await Guild.find({ take: Math.abs(Number(limit || configLimit)) })
: await Guild.find({ where: `"features" LIKE '%DISCOVERABLE%'`, take: Math.abs(Number(limit || configLimit)) });
} else {
guilds = showAllGuilds
? await Guild.find({ where: `"primary_category_id" = ${categories}`, take: Math.abs(Number(limit || configLimit)) })
: await Guild.find({
where: `"primary_category_id" = ${categories} AND "features" LIKE '%DISCOVERABLE%'`,
take: Math.abs(Number(limit || configLimit))
});
}
const total = guilds ? guilds.length : undefined;
res.send({ total: total, guilds: guilds, offset: Number(offset || Config.get().guild.discovery.offset), limit: Number(limit || configLimit) });
});
export default router;
-75
View File
@@ -1,75 +0,0 @@
{
"exclude": ["node_modules"],
"include": ["src/**/*.ts"],
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
"incremental": true /* Enable incremental compilation */,
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
"lib": ["ES2021"] /* Specify library files to be included in the compilation. */,
"allowJs": true /* Allow javascript files to be compiled. */,
"checkJs": true /* Report errors in .js files. */,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true /* Generates corresponding '.d.ts' file. */,
"declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */,
"sourceMap": true /* Generates corresponding '.map' file. */,
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist/" /* Redirect output structure to the directory. */,
"rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"strictNullChecks": true /* Enable strict null checks. */,
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
"types": ["node"] /* Type declaration files to be included in compilation. */,
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
"baseUrl": ".",
"paths": {
"@fosscord/api": ["src/index"]
},
"plugins": [{ "transform": "@zerollup/ts-transform-paths" }],
"experimentalDecorators": true
}
}
File renamed without changes.
+44
View File
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html class="theme-dark" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no" name="viewport" />
<link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" />
<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" />
<title>Discord Test Client Developer Portal</title>
<meta charset="utf-8" data-react-helmet="true" />
</head>
<body>
<div id="app-mount"></div>
<script>
window.GLOBAL_ENV = {
API_VERSION: 9,
API_ENDPOINT: "/api",
WEBAPP_ENDPOINT: "",
CDN_HOST: `${location.hostname}:3003`,
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
MARKETING_ENDPOINT: "//discord.com",
RELEASE_CHANNEL: "stable",
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0"
};
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
const localStorage = window.localStorage;
// TODO: remote auth
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
localStorage.setItem(
"DeveloperOptionsStore",
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
);
</script>
<script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script>
<script src="/assets/aa190934324e05fcc35c.js" integrity=""></script>
<script src="/assets/45664a0209e828a528b4.js" integrity=""></script>
</body>
</html>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+84
View File
@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Discord Test Client</title>
<link rel="stylesheet" href="/assets/fosscord.css" />
<link id="logincss" rel="stylesheet" href="/assets/fosscord-login.css" />
<link id="customcss" rel="stylesheet" href="/assets/user.css" />
<!-- inline plugin marker -->
<!-- preload plugin marker -->
</head>
<body>
<div id="app-mount"></div>
<script>
window.__OVERLAY__ = /overlay/.test(location.pathname);
window.__BILLING_STANDALONE__ = /^\/billing/.test(location.pathname);
window.GLOBAL_ENV = {
API_ENDPOINT: "/api",
API_VERSION: 9,
GATEWAY_ENDPOINT: `${location.protocol === "https:" ? "wss://" : "ws://"}${location.host}`,
WEBAPP_ENDPOINT: "",
CDN_HOST: `${location.hostname}:3003`,
ASSET_ENDPOINT: "",
MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net",
WIDGET_ENDPOINT: `//${location.host}/widget`,
INVITE_HOST: `${location.hostname}/invite`,
GUILD_TEMPLATE_HOST: "${location.host}",
GIFT_CODE_HOST: "${location.hostname}",
RELEASE_CHANNEL: "stable",
MARKETING_ENDPOINT: "//discord.com",
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
NETWORKING_ENDPOINT: "//router.discordapp.net",
RTC_LATENCY_ENDPOINT: "//${location.hostname}/rtc",
ACTIVITY_APPLICATION_HOST: 'discordsays.com',
PROJECT_ENV: "production",
REMOTE_AUTH_ENDPOINT: "//localhost:3020",
SENTRY_TAGS: { buildId: "75e36d9", buildType: "normal" },
MIGRATION_SOURCE_ORIGIN: "https://${location.hostname}",
MIGRATION_DESTINATION_ORIGIN: "https://${location.hostname}",
HTML_TIMESTAMP: Date.now(),
ALGOLIA_KEY: "aca0d7082e4e63af5ba5917d5e96bed0",
};
GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST;
const localStorage = window.localStorage;
// TODO: remote auth
// window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, "");
localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT);
localStorage.setItem(
"DeveloperOptionsStore",
`{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}`
);
setInterval(() => {
let token = JSON.parse(localStorage.getItem("token"));
if (token) {
let logincss = document.querySelector('#logincss'),
canRemove = logincss ? logincss : "";
if (canRemove !== "") {
document.querySelector("#logincss").remove();
canRemove = "";
}
}
}, 1000)
const settings = JSON.parse(localStorage.getItem("UserSettingsStore"));
if (settings && settings.locale.length <= 2) {
// fix client locale wrong and client not loading at all
settings.locale = "en-US";
localStorage.setItem("UserSettingsStore", JSON.stringify(settings));
}
</script>
<script src="/assets/checkLocale.js"></script>
<script src="/assets/2f2e0c25e45eb2f5a6f1.js"></script>
<script src="/assets/006e72c08a4c69cb66fc.js"></script>
<script src="/assets/2f94a3ba801087653a38.js"></script>
<script src="/assets/f7703f092bdbfc607cc7.js"></script>
<!-- plugin marker -->
</body>
</html>
@@ -44,7 +44,7 @@ function _generateName() {
return `${prefix.random()}${suffix.random()}`;
}
var token = JSON.parse(localStorage.getItem("token"));
let token = JSON.parse(localStorage.getItem("token"));
if (!token && location.pathname !== "/login" && location.pathname !== "/register") {
fetch(`${window.GLOBAL_ENV.API_ENDPOINT}/auth/register`, {
method: "POST",
@@ -6,7 +6,7 @@
// fosscord-login.css after login is successful, but not if you reload the page after logging in. This script is to remove fosscord-login.css in
// that specific case.
var token = JSON.parse(localStorage.getItem("token"));
let token = JSON.parse(localStorage.getItem("token"));
if (!token && location.pathname !== "/login" && location.pathname !== "/register") {
document.getElementById("logincss").remove();
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+18
View File
@@ -0,0 +1,18 @@
{
"login": {
"INVALID_LOGIN": "Дадзены адрас электроннай пошты ці тэлефона не знойдзены",
"INVALID_PASSWORD": "Няправільны пароль",
"ACCOUNT_DISABLED": "Гэты ўліковы запіс адключаны",
"INVALID_TOTP_CODE": "Няправільны код двухфактарнай аўтэнтыфікацыі.",
"INVALID_TOTP_SECRET": "Няправільны сакрэтны код двухфактарнай аўтэнтыфікацыі."
},
"register": {
"REGISTRATION_DISABLED": "Рэгістрацыя новых карыстальнікаў адключана",
"INVITE_ONLY": "Вас павінны запрасіць, каб зарэгістравацца",
"EMAIL_INVALID": "Няправільны адрас электроннай пошты",
"EMAIL_ALREADY_REGISTERED": "Дадзены адрас электроннай пошты ўжо зарэгістраваны",
"DATE_OF_BIRTH_UNDERAGE": "Вам павінна быць не менш за {{years}} гадоў",
"CONSENT_REQUIRED": "Вы павінны пагадзіцца з Умовамі прадастаўлення паслуг і Палітыкай прыватнасці.",
"USERNAME_TOO_MANY_USERS": "Занадта шмат карыстальнікаў маюць гэтае імя карыстальніка, калі ласка, паспрабуйце іншае"
}
}
@@ -1,9 +1,9 @@
{
"field": {
"BASE_TYPE_REQUIRED": "This field is required",
"BASE_TYPE_STRING": "This field must be a string",
"BASE_TYPE_NUMBER": "This field must be a number",
"BASE_TYPE_BIGINT": "This field must be a bigint",
"BASE_TYPE_REQUIRED": "Гэта поле з'яўляецца абавязковым",
"BASE_TYPE_STRING": "Гэта поле павінна быць радком",
"BASE_TYPE_NUMBER": "Гэта поле павінна быць лікам",
"BASE_TYPE_BIGINT": "Гэта поле павінна быць bigint",
"BASE_TYPE_BOOLEAN": "This field must be a boolean",
"BASE_TYPE_CHOICES": "This field must be one of ({{types}})",
"BASE_TYPE_CLASS": "This field must be an instance of {{type}}",
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+18
View File
@@ -0,0 +1,18 @@
{
"login": {
"INVALID_LOGIN": "E-Mail oder Telefonnummer nicht gefunden",
"INVALID_PASSWORD": "Ungültiges Passwort",
"ACCOUNT_DISABLED": "Dieses Konto ist deaktiviert",
"INVALID_TOTP_CODE": "Ungültiger Zwei-Faktor-Code.",
"INVALID_TOTP_SECRET": "Ungültiges Zwei-Faktor-Secret."
},
"register": {
"REGISTRATION_DISABLED": "Die Registrierung neuer Benutzer ist deaktiviert",
"INVITE_ONLY": "Du musst eingeladen werden, um dich zu registrieren",
"EMAIL_INVALID": "Ungültige E-Mail Adresse",
"EMAIL_ALREADY_REGISTERED": "Die E-Mail Adresse wird bereits verwendet",
"DATE_OF_BIRTH_UNDERAGE": "Du musst mindestens {{years}} Jahre alt sein",
"CONSENT_REQUIRED": "Du musst den Nutzungsbedingungen und den Datenschutzbestimmungen zustimmen.",
"USERNAME_TOO_MANY_USERS": "Dieser Name wird von zu vielen Nutzern verwendet, bitte wähle einen anderen"
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"field": {
"BASE_TYPE_REQUIRED": "Dieses Feld ist erforderlich",
"BASE_TYPE_STRING": "Dieses Feld muss ein String sein",
"BASE_TYPE_NUMBER": "Dieses Feld muss eine Zahl sein",
"BASE_TYPE_BIGINT": "Dieses Feld muss ein Bigint sein",
"BASE_TYPE_BOOLEAN": "Dieses Feld muss ein Boolean sein",
"BASE_TYPE_CHOICES": "Dieses Feld muss eines von ({{types}}) sein",
"BASE_TYPE_CLASS": "Dieses Feld muss eine Instanz von {{type}} sein",
"BASE_TYPE_OBJECT": "Dieses Feld muss ein Objekt sein",
"BASE_TYPE_ARRAY": "Dieses Feld muss ein Array sein",
"UNKOWN_FIELD": "Unbekanntes Feld: {{key}}",
"BASE_TYPE_CONSTANT": "Dieses Feld muss {{value}} sein",
"EMAIL_TYPE_INVALID_EMAIL": "Keine wohlgeformte E-Mail-Adresse",
"DATE_TYPE_PARSE": "Konnte {{date}} nicht verarbeiten. Es muss dem ISO8601 Standard entsprechen",
"BASE_TYPE_BAD_LENGTH": "Muss zwischen {{length}} lang sein"
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 671 files, more files were not shown because too many files have changed in this diff. Show more