mirror of
https://github.com/PretendoNetwork/miiverse-api.git
synced 2026-04-25 15:46:52 -05:00
Removed JSON config, moved to env vars
This commit is contained in:
parent
f70cd34406
commit
93008c5a1a
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -131,6 +131,5 @@ dist
|
|||
|
||||
# custom
|
||||
certs
|
||||
config.json
|
||||
src/logs
|
||||
dist
|
||||
dist
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"http": {
|
||||
"port": 8080
|
||||
},
|
||||
"account_server": "localhost",
|
||||
"account_server_secret": "",
|
||||
"X-Nintendo-Client-ID": "",
|
||||
"X-Nintendo-Client-Secret": "",
|
||||
"mongoose": {
|
||||
"uri": "mongodb://localhost:27017",
|
||||
"database": "Juxt",
|
||||
"options": {
|
||||
"useNewUrlParser": true,
|
||||
"useUnifiedTopology": true
|
||||
}
|
||||
},
|
||||
"account_db": {
|
||||
"uri": "mongodb://localhost:27017",
|
||||
"database": "pretendo",
|
||||
"options": {
|
||||
"useNewUrlParser": true,
|
||||
"useUnifiedTopology": true
|
||||
}
|
||||
},
|
||||
"aws": {
|
||||
"spaces": {
|
||||
"key": "",
|
||||
"secret": ""
|
||||
}
|
||||
},
|
||||
"grpc": {
|
||||
"friends": {
|
||||
"ip": "localhost",
|
||||
"port": 50051,
|
||||
"api_key": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
80
package-lock.json
generated
80
package-lock.json
generated
|
|
@ -13,11 +13,11 @@
|
|||
"bmp-js": "^0.1.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"colors": "^1.4.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.0",
|
||||
"express-subdomain": "^1.0.5",
|
||||
"fs-extra": "^9.0.0",
|
||||
"grpc": "github:pretendonetwork/grpc-js",
|
||||
"memoizee": "^0.4.15",
|
||||
"moment": "^2.24.0",
|
||||
"moment-timezone": "^0.5.27",
|
||||
|
|
@ -37,8 +37,13 @@
|
|||
"xmlbuilder2": "0.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bmp-js": "^0.1.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/node-rsa": "^1.1.1",
|
||||
"@types/pako": "^2.0.0",
|
||||
"@types/pngjs": "^6.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"eslint": "^8.38.0",
|
||||
|
|
@ -1445,6 +1450,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"node_modules/@types/bmp-js": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/bmp-js/-/bmp-js-0.1.0.tgz",
|
||||
"integrity": "sha512-uMU85ROcmlY1f4mVPTlNodRXa6Z5f0AIxvv5b0pvjty3KNg7ljf5lNSspHgaF6iFDCiGpLQmJna+VwEpUC9TyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/body-parser": {
|
||||
"version": "1.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||
|
|
@ -1487,12 +1501,31 @@
|
|||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz",
|
||||
"integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/jsonfile": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/jsonfile": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz",
|
||||
"integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
|
|
@ -1518,6 +1551,30 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
|
||||
"integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
|
||||
},
|
||||
"node_modules/@types/node-rsa": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-rsa/-/node-rsa-1.1.1.tgz",
|
||||
"integrity": "sha512-itzxtaBgk4OMbrCawVCvas934waMZWjW17v7EYgFVlfYS/cl0/P7KZdojWCq9SDJMI5cnLQLUP8ayhVCTY8TEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pako": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz",
|
||||
"integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/pngjs": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.1.tgz",
|
||||
"integrity": "sha512-J39njbdW1U/6YyVXvC9+1iflZghP8jgRf2ndYghdJb5xL49LYDB+1EuAxfbuJ2IBbWIL3AjHPQhgaTxT3YaYeg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
|
|
@ -2497,6 +2554,14 @@
|
|||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
|
|
@ -3337,19 +3402,6 @@
|
|||
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/grpc": {
|
||||
"name": "pretendo-grpc",
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+ssh://git@github.com/pretendonetwork/grpc-js.git#ea933171998bd8093a6a8ba1d57691af85a36cc0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.6.9",
|
||||
"@grpc/proto-loader": "^0.7.0",
|
||||
"long": "^5.2.0",
|
||||
"nice-grpc": "^2.0.0",
|
||||
"protobufjs": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"bmp-js": "^0.1.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"colors": "^1.4.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.0",
|
||||
"express-subdomain": "^1.0.5",
|
||||
|
|
@ -41,8 +42,13 @@
|
|||
"xmlbuilder2": "0.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bmp-js": "^0.1.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/node-rsa": "^1.1.1",
|
||||
"@types/pako": "^2.0.0",
|
||||
"@types/pngjs": "^6.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"eslint": "^8.38.0",
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import mongoose from 'mongoose';
|
||||
import { LOG_INFO, LOG_ERROR } from '@/logger';
|
||||
import { account_db as mongooseConfig } from '../config.json';
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
const { uri, database, options } = mongooseConfig;
|
||||
const { account_db: mongooseConfig } = config;
|
||||
|
||||
export let pnidConnection: mongoose.Connection;
|
||||
|
||||
export function connect() {
|
||||
if(!pnidConnection)
|
||||
pnidConnection = makeNewConnection(`${uri}/${database}`);
|
||||
pnidConnection = makeNewConnection(mongooseConfig.connection_string);
|
||||
}
|
||||
|
||||
export function verifyConnected() {
|
||||
|
|
@ -18,7 +18,7 @@ export function verifyConnected() {
|
|||
}
|
||||
|
||||
export function makeNewConnection(uri) {
|
||||
pnidConnection = mongoose.createConnection(uri, options as mongoose.ConnectOptions);
|
||||
pnidConnection = mongoose.createConnection(uri, mongooseConfig.options);
|
||||
|
||||
pnidConnection.on('error', function (error) {
|
||||
LOG_ERROR(`MongoDB connection ${this.name} ${JSON.stringify(error)}`);
|
||||
|
|
@ -36,4 +36,4 @@ export function makeNewConnection(uri) {
|
|||
return pnidConnection;
|
||||
}
|
||||
|
||||
pnidConnection = makeNewConnection(`${uri}/${database}`);
|
||||
pnidConnection = makeNewConnection(mongooseConfig.connection_string);
|
||||
|
|
|
|||
111
src/config-manager.ts
Normal file
111
src/config-manager.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import fs from 'fs-extra';
|
||||
import mongoose from 'mongoose';
|
||||
import dotenv from 'dotenv';
|
||||
import { LOG_INFO, LOG_WARN, LOG_ERROR } from '@/logger';
|
||||
import { Config } from '@/types/common/config';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
LOG_INFO('Loading config');
|
||||
|
||||
let mongooseConnectOptionsMain: mongoose.ConnectOptions = {};
|
||||
|
||||
if (process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) {
|
||||
mongooseConnectOptionsMain = fs.readJSONSync(process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH);
|
||||
} else {
|
||||
LOG_WARN('No Mongoose connection options found for main connection. To add connection options, set PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH to the path of your options JSON file');
|
||||
}
|
||||
|
||||
let mongooseConnectOptionsAccount: mongoose.ConnectOptions = {};
|
||||
|
||||
if (process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_ACCOUNT_SERVER_CONNECT_OPTIONS_PATH) {
|
||||
mongooseConnectOptionsAccount = fs.readJSONSync(process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_ACCOUNT_SERVER_CONNECT_OPTIONS_PATH);
|
||||
} else {
|
||||
LOG_WARN('No Mongoose connection options found for main connection. To add connection options, set PN_MIIVERSE_API_CONFIG_MONGOOSE_ACCOUNT_SERVER_CONNECT_OPTIONS_PATH to the path of your options JSON file');
|
||||
}
|
||||
|
||||
|
||||
export const config: Config = {
|
||||
http: {
|
||||
port: Number(process.env.PN_MIIVERSE_API_CONFIG_HTTP_PORT || '')
|
||||
},
|
||||
account_server_address: process.env.PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_ADDRESS || '',
|
||||
account_server_secret: process.env.PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_SECRET || '',
|
||||
mongoose: {
|
||||
connection_string: process.env.PN_MIIVERSE_API_CONFIG_MONGO_CONNECTION_STRING || '',
|
||||
options: mongooseConnectOptionsMain
|
||||
},
|
||||
account_db: {
|
||||
connection_string: process.env.PN_MIIVERSE_API_CONFIG_MONGO_ACCOUNT_SERVER_CONNECTION_STRING || '',
|
||||
options: mongooseConnectOptionsAccount
|
||||
},
|
||||
s3: {
|
||||
endpoint: process.env.PN_MIIVERSE_API_CONFIG_S3_ENDPOINT || '',
|
||||
key: process.env.PN_MIIVERSE_API_CONFIG_S3_ACCESS_KEY || '',
|
||||
secret: process.env.PN_MIIVERSE_API_CONFIG_S3_ACCESS_SECRET || ''
|
||||
},
|
||||
grpc: {
|
||||
friends: {
|
||||
ip: process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_IP || '',
|
||||
port: Number(process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_PORT || ''),
|
||||
api_key: process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_API_KEY || ''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LOG_INFO('Config loaded, checking integrity');
|
||||
|
||||
if (!config.http.port) {
|
||||
LOG_ERROR('Failed to find HTTP port. Set the PN_MIIVERSE_API_CONFIG_HTTP_PORT environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.account_server_address) {
|
||||
LOG_ERROR('Failed to find account server address. Set the PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_ADDRESS environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.account_server_secret) {
|
||||
LOG_ERROR('Failed to find account server secret. Set the PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_SECRET environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.mongoose.connection_string) {
|
||||
LOG_ERROR('Failed to find MongoDB connection string. Set the PN_MIIVERSE_API_CONFIG_MONGO_CONNECTION_STRING environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.account_db.connection_string) {
|
||||
LOG_ERROR('Failed to find MongoDB Account Server connection string. Set the PN_MIIVERSE_API_CONFIG_MONGO_ACCOUNT_SERVER_CONNECTION_STRING environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.s3.endpoint) {
|
||||
LOG_ERROR('Failed to find s3 endpoint. Set the PN_MIIVERSE_API_CONFIG_S3_ENDPOINT environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.s3.key) {
|
||||
LOG_ERROR('Failed to find s3 key. Set the PN_MIIVERSE_API_CONFIG_S3_ACCESS_KEY environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.s3.secret) {
|
||||
LOG_ERROR('Failed to find s3 secret. Set the PN_MIIVERSE_API_CONFIG_S3_ACCESS_SECRET environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.grpc.friends.ip) {
|
||||
LOG_ERROR('Failed to find NEX Friends gRPC ip. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_IP environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.grpc.friends.port) {
|
||||
LOG_ERROR('Failed to find NEX Friends gRPC port. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_PORT environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.grpc.friends.api_key) {
|
||||
LOG_ERROR('Failed to find NEX Friends gRPC API key. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_API_KEY environment variable');
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
@ -9,15 +9,14 @@ import { Notification } from '@/models/notification';
|
|||
import { PNID } from '@/models/pnid';
|
||||
import { Post } from '@/models/post';
|
||||
import { Settings } from '@/models/settings';
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
import { mongoose as mongooseConfig } from '../config.json';
|
||||
|
||||
const { uri, database, options } = mongooseConfig;
|
||||
const { mongoose: mongooseConfig } = config;
|
||||
|
||||
let connection;
|
||||
|
||||
export async function connect() {
|
||||
await mongoose.connect(`${uri}/${database}`, options as mongoose.ConnectOptions || {});
|
||||
await mongoose.connect(mongooseConfig.connection_string, mongooseConfig.options);
|
||||
connection = mongoose.connection;
|
||||
connection.on('connected', function () {
|
||||
LOG_INFO(`MongoDB connected ${this.name}`);
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ import morgan from 'morgan';
|
|||
import xml from 'object-to-xml';
|
||||
import { connect as connectDatabase } from '@/database';
|
||||
import { LOG_INFO, LOG_SUCCESS } from '@/logger';
|
||||
import config from '../config.json';
|
||||
import xmlparser from '@/middleware/xml-parser';
|
||||
import auth from '@/middleware/auth';
|
||||
|
||||
import miiverse from '@/services/miiverse-api';
|
||||
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
const { http: { port } } = config;
|
||||
const app = express();
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ router.post('/', upload.none(), async function (req, res) {
|
|||
return res.redirect(`/friend_messages/${conversation.id}`);
|
||||
}
|
||||
let paramPackData = decodeParamPack(req.headers["x-nintendo-parampack"]);
|
||||
let appData = "", painting = "", paintingURI = "", screenshot = null;
|
||||
let appData = "", painting = "", paintingURI, screenshot = null;
|
||||
if (req.body.app_data)
|
||||
appData = req.body.app_data.replace(/[^A-Za-z0-9+/=\s]/g, "");
|
||||
if (req.body.painting) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ async function newPost(req, res) {
|
|||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
let appData = "", painting = "", paintingURI = "", screenshot = null;
|
||||
let appData = "", painting = "", paintingURI, screenshot = null;
|
||||
if (req.body.app_data)
|
||||
appData = req.body.app_data.replace(/[^A-Za-z0-9+/=\s]/g, "");
|
||||
if (req.body.painting) {
|
||||
|
|
|
|||
29
src/types/common/config.ts
Normal file
29
src/types/common/config.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import mongoose from 'mongoose';
|
||||
|
||||
export interface Config {
|
||||
http: {
|
||||
port: number;
|
||||
};
|
||||
account_server_address: string;
|
||||
account_server_secret: string;
|
||||
mongoose: {
|
||||
connection_string: string;
|
||||
options: mongoose.ConnectOptions;
|
||||
};
|
||||
account_db: {
|
||||
connection_string: string;
|
||||
options: mongoose.ConnectOptions;
|
||||
};
|
||||
s3: {
|
||||
endpoint: string;
|
||||
key: string;
|
||||
secret: string;
|
||||
};
|
||||
grpc: {
|
||||
friends: {
|
||||
ip: string;
|
||||
port: number;
|
||||
api_key: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
2
src/types/express.d.ts
vendored
2
src/types/express.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// to make the file a module and avoid the TypeScript error
|
||||
export {}
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
|
|
|
|||
3
src/types/object-to-xml.d.ts
vendored
Normal file
3
src/types/object-to-xml.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
declare module 'object-to-xml';
|
||||
|
||||
// TODO - Add proper types
|
||||
3
src/types/tga.d.ts
vendored
Normal file
3
src/types/tga.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
declare module 'tga';
|
||||
|
||||
// TODO - Add proper types
|
||||
347
src/util.ts
347
src/util.ts
|
|
@ -5,7 +5,7 @@ import fs from 'fs-extra';
|
|||
import TGA from 'tga';
|
||||
import pako from 'pako';
|
||||
import { PNG } from 'pngjs';
|
||||
import bmp from "bmp-js";
|
||||
import bmp from 'bmp-js';
|
||||
import aws from 'aws-sdk';
|
||||
import { createChannel, createClient, Metadata } from 'nice-grpc';
|
||||
import { FriendsDefinition } from 'pretendo-grpc-ts/src/friends/friends_service';
|
||||
|
|
@ -17,241 +17,234 @@ import { Content } from '@/models/content';
|
|||
import { SafeQs } from '@/types/common/safe-qs';
|
||||
import { ParamPack } from '@/types/common/param-pack';
|
||||
|
||||
const config = require('../../config.json');
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
const { ip, port, api_key } = config.grpc.friends;
|
||||
const channel = createChannel(`${ip}:${port}`);
|
||||
const client = createClient(FriendsDefinition, channel);
|
||||
|
||||
const spacesEndpoint = new aws.Endpoint('nyc3.digitaloceanspaces.com');
|
||||
const s3 = new aws.S3({
|
||||
endpoint: spacesEndpoint,
|
||||
accessKeyId: config.aws.spaces.key,
|
||||
secretAccessKey: config.aws.spaces.secret
|
||||
endpoint: new aws.Endpoint(config.s3.endpoint),
|
||||
accessKeyId: config.s3.key,
|
||||
secretAccessKey: config.s3.secret
|
||||
});
|
||||
|
||||
export async function create_user(pid, experience, notifications, region) {
|
||||
const pnid = await getPNID(pid);
|
||||
if(!pnid)
|
||||
return;
|
||||
let newSettings = {
|
||||
pid: pid,
|
||||
screen_name: pnid.mii.name,
|
||||
game_skill: experience,
|
||||
receive_notifications: notifications,
|
||||
}
|
||||
let newContent = {
|
||||
pid: pid
|
||||
}
|
||||
const newSettingsObj = new Settings(newSettings);
|
||||
await newSettingsObj.save();
|
||||
const pnid = await getPNID(pid);
|
||||
if (!pnid) {
|
||||
return;
|
||||
}
|
||||
const newSettings = {
|
||||
pid: pid,
|
||||
screen_name: pnid.mii.name,
|
||||
game_skill: experience,
|
||||
receive_notifications: notifications,
|
||||
};
|
||||
const newContent = {
|
||||
pid: pid
|
||||
};
|
||||
const newSettingsObj = new Settings(newSettings);
|
||||
await newSettingsObj.save();
|
||||
|
||||
const newContentObj = new Content(newContent);
|
||||
await newContentObj.save();
|
||||
const newContentObj = new Content(newContent);
|
||||
await newContentObj.save();
|
||||
}
|
||||
|
||||
export function decodeParamPack(paramPack): ParamPack {
|
||||
/* Decode base64 */
|
||||
let dec = Buffer.from(paramPack, "base64").toString("ascii").slice(1, -1).split("\\");
|
||||
/* Remove starting and ending '/', split into array */
|
||||
/* Parameters are in the format [name, val, name, val]. Copy into out{}. */
|
||||
const out = {};
|
||||
for (let i = 0; i < dec.length; i += 2) {
|
||||
out[dec[i].trim()] = dec[i + 1].trim();
|
||||
}
|
||||
return out as ParamPack;
|
||||
/* Decode base64 */
|
||||
const dec = Buffer.from(paramPack, 'base64').toString('ascii').slice(1, -1).split('\\');
|
||||
/* Remove starting and ending '/', split into array */
|
||||
/* Parameters are in the format [name, val, name, val]. Copy into out{}. */
|
||||
const out = {};
|
||||
for (let i = 0; i < dec.length; i += 2) {
|
||||
out[dec[i].trim()] = dec[i + 1].trim();
|
||||
}
|
||||
return out as ParamPack;
|
||||
}
|
||||
|
||||
export function processServiceToken(token) {
|
||||
try
|
||||
{
|
||||
let B64token = Buffer.from(token, 'base64');
|
||||
let decryptedToken = this.decryptToken(B64token);
|
||||
return decryptedToken.readUInt32LE(0x2);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const B64token = Buffer.from(token, 'base64');
|
||||
const decryptedToken = this.decryptToken(B64token);
|
||||
return decryptedToken.readUInt32LE(0x2);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function decryptToken(token) {
|
||||
// Access and refresh tokens use a different format since they must be much smaller
|
||||
// Assume a small length means access or refresh token
|
||||
if (token.length <= 32) {
|
||||
const cryptoPath = `${__dirname}/../certs/access`;
|
||||
const aesKey = Buffer.from(fs.readFileSync(`${cryptoPath}/aes.key`, { encoding: 'utf8' }), 'hex');
|
||||
// Access and refresh tokens use a different format since they must be much smaller
|
||||
// Assume a small length means access or refresh token
|
||||
if (token.length <= 32) {
|
||||
const cryptoPath = `${__dirname}/../certs/access`;
|
||||
const aesKey = Buffer.from(fs.readFileSync(`${cryptoPath}/aes.key`, { encoding: 'utf8' }), 'hex');
|
||||
|
||||
const iv = Buffer.alloc(16);
|
||||
const iv = Buffer.alloc(16);
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv);
|
||||
const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv);
|
||||
|
||||
let decryptedBody = decipher.update(token);
|
||||
decryptedBody = Buffer.concat([decryptedBody, decipher.final()]);
|
||||
let decryptedBody = decipher.update(token);
|
||||
decryptedBody = Buffer.concat([decryptedBody, decipher.final()]);
|
||||
|
||||
return decryptedBody;
|
||||
}
|
||||
return decryptedBody;
|
||||
}
|
||||
|
||||
const cryptoPath = `${__dirname}/../certs/access`;
|
||||
const cryptoPath = `${__dirname}/../certs/access`;
|
||||
|
||||
const cryptoOptions = {
|
||||
private_key: fs.readFileSync(`${cryptoPath}/private.pem`),
|
||||
hmac_secret: config.account_server_secret
|
||||
};
|
||||
const cryptoOptions = {
|
||||
private_key: fs.readFileSync(`${cryptoPath}/private.pem`),
|
||||
hmac_secret: config.account_server_secret
|
||||
};
|
||||
|
||||
const privateKey = new NodeRSA(cryptoOptions.private_key, 'pkcs1-private-pem', {
|
||||
environment: 'browser',
|
||||
encryptionScheme: {
|
||||
'hash': 'sha256',
|
||||
}
|
||||
});
|
||||
const privateKey = new NodeRSA(cryptoOptions.private_key, 'pkcs1-private-pem', {
|
||||
environment: 'browser',
|
||||
encryptionScheme: {
|
||||
scheme: 'pkcs1_oaep',
|
||||
hash: 'sha256'
|
||||
}
|
||||
});
|
||||
|
||||
const cryptoConfig = token.subarray(0, 0x82);
|
||||
const signature = token.subarray(0x82, 0x96);
|
||||
const encryptedBody = token.subarray(0x96);
|
||||
const cryptoConfig = token.subarray(0, 0x82);
|
||||
const signature = token.subarray(0x82, 0x96);
|
||||
const encryptedBody = token.subarray(0x96);
|
||||
|
||||
const encryptedAESKey = cryptoConfig.subarray(0, 128);
|
||||
const point1 = cryptoConfig.readInt8(0x80);
|
||||
const point2 = cryptoConfig.readInt8(0x81);
|
||||
const encryptedAESKey = cryptoConfig.subarray(0, 128);
|
||||
const point1 = cryptoConfig.readInt8(0x80);
|
||||
const point2 = cryptoConfig.readInt8(0x81);
|
||||
|
||||
const iv = Buffer.concat([
|
||||
Buffer.from(encryptedAESKey.subarray(point1, point1 + 8)),
|
||||
Buffer.from(encryptedAESKey.subarray(point2, point2 + 8))
|
||||
]);
|
||||
const iv = Buffer.concat([
|
||||
Buffer.from(encryptedAESKey.subarray(point1, point1 + 8)),
|
||||
Buffer.from(encryptedAESKey.subarray(point2, point2 + 8))
|
||||
]);
|
||||
|
||||
try {
|
||||
const decryptedAESKey = privateKey.decrypt(encryptedAESKey);
|
||||
try {
|
||||
const decryptedAESKey = privateKey.decrypt(encryptedAESKey);
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv);
|
||||
const decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv);
|
||||
|
||||
let decryptedBody = decipher.update(encryptedBody);
|
||||
decryptedBody = Buffer.concat([decryptedBody, decipher.final()]);
|
||||
let decryptedBody = decipher.update(encryptedBody);
|
||||
decryptedBody = Buffer.concat([decryptedBody, decipher.final()]);
|
||||
|
||||
const hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(decryptedBody);
|
||||
const calculatedSignature = hmac.digest();
|
||||
const hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(decryptedBody);
|
||||
const calculatedSignature = hmac.digest();
|
||||
|
||||
if (Buffer.compare(calculatedSignature, signature) !== 0) {
|
||||
LOG_ERROR('Token signature did not match');
|
||||
return null;
|
||||
}
|
||||
if (Buffer.compare(calculatedSignature, signature) !== 0) {
|
||||
LOG_ERROR('Token signature did not match');
|
||||
return null;
|
||||
}
|
||||
|
||||
return decryptedBody;
|
||||
}
|
||||
catch (e) {
|
||||
LOG_ERROR('Failed to decrypt token. Probably a NNID from the topics request');
|
||||
return null;
|
||||
}
|
||||
return decryptedBody;
|
||||
} catch (e) {
|
||||
LOG_ERROR('Failed to decrypt token. Probably a NNID from the topics request');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function processPainting(painting, isTGA) {
|
||||
if (isTGA) {
|
||||
let paintingBuffer = Buffer.from(painting, 'base64');
|
||||
let output = '';
|
||||
try {
|
||||
output = pako.inflate(paintingBuffer);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
let tga = new TGA(Buffer.from(output));
|
||||
let png = new PNG({
|
||||
width: tga.width,
|
||||
height: tga.height
|
||||
});
|
||||
png.data = tga.pixels;
|
||||
return PNG.sync.write(png);
|
||||
//return `data:image/png;base64,${pngBuffer.toString('base64')}`;
|
||||
}
|
||||
else {
|
||||
let paintingBuffer = Buffer.from(painting, 'base64');
|
||||
let bitmap = bmp.decode(paintingBuffer)
|
||||
const tga = this.createBMPTgaBuffer(bitmap.width, bitmap.height, bitmap.data, false);
|
||||
if (isTGA) {
|
||||
const paintingBuffer = Buffer.from(painting, 'base64');
|
||||
let output;
|
||||
try {
|
||||
output = pako.inflate(paintingBuffer);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const tga = new TGA(Buffer.from(output));
|
||||
const png = new PNG({
|
||||
width: tga.width,
|
||||
height: tga.height
|
||||
});
|
||||
png.data = tga.pixels;
|
||||
return PNG.sync.write(png);
|
||||
//return `data:image/png;base64,${pngBuffer.toString('base64')}`;
|
||||
} else {
|
||||
const paintingBuffer = Buffer.from(painting, 'base64');
|
||||
const bitmap = bmp.decode(paintingBuffer);
|
||||
const tga = this.createBMPTgaBuffer(bitmap.width, bitmap.height, bitmap.data, false);
|
||||
|
||||
let output;
|
||||
try
|
||||
{
|
||||
output = pako.deflate(tga, {level: 6});
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
console.error(err);
|
||||
}
|
||||
let output;
|
||||
try {
|
||||
output = pako.deflate(tga, {level: 6});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return new Buffer(output).toString('base64')
|
||||
}
|
||||
return new Buffer(output).toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
export function nintendoPasswordHash(password, pid) {
|
||||
const pidBuffer = Buffer.alloc(4);
|
||||
pidBuffer.writeUInt32LE(pid);
|
||||
const pidBuffer = Buffer.alloc(4);
|
||||
pidBuffer.writeUInt32LE(pid);
|
||||
|
||||
const unpacked = Buffer.concat([
|
||||
pidBuffer,
|
||||
Buffer.from('\x02\x65\x43\x46'),
|
||||
Buffer.from(password)
|
||||
]);
|
||||
return crypto.createHash('sha256').update(unpacked).digest().toString('hex');
|
||||
const unpacked = Buffer.concat([
|
||||
pidBuffer,
|
||||
Buffer.from('\x02\x65\x43\x46'),
|
||||
Buffer.from(password)
|
||||
]);
|
||||
return crypto.createHash('sha256').update(unpacked).digest().toString('hex');
|
||||
}
|
||||
|
||||
export function createBMPTgaBuffer(width, height, pixels, dontFlipY) {
|
||||
var buffer = Buffer.alloc(18 + pixels.length);
|
||||
// write header
|
||||
buffer.writeInt8(0, 0);
|
||||
buffer.writeInt8(0, 1);
|
||||
buffer.writeInt8(2, 2);
|
||||
buffer.writeInt16LE(0, 3);
|
||||
buffer.writeInt16LE(0, 5);
|
||||
buffer.writeInt8(0, 7);
|
||||
buffer.writeInt16LE(0, 8);
|
||||
buffer.writeInt16LE(0, 10);
|
||||
buffer.writeInt16LE(width, 12);
|
||||
buffer.writeInt16LE(height, 14);
|
||||
buffer.writeInt8(32, 16);
|
||||
buffer.writeInt8(8, 17);
|
||||
const buffer = Buffer.alloc(18 + pixels.length);
|
||||
// write header
|
||||
buffer.writeInt8(0, 0);
|
||||
buffer.writeInt8(0, 1);
|
||||
buffer.writeInt8(2, 2);
|
||||
buffer.writeInt16LE(0, 3);
|
||||
buffer.writeInt16LE(0, 5);
|
||||
buffer.writeInt8(0, 7);
|
||||
buffer.writeInt16LE(0, 8);
|
||||
buffer.writeInt16LE(0, 10);
|
||||
buffer.writeInt16LE(width, 12);
|
||||
buffer.writeInt16LE(height, 14);
|
||||
buffer.writeInt8(32, 16);
|
||||
buffer.writeInt8(8, 17);
|
||||
|
||||
var offset = 18;
|
||||
for (var i = 0; i < height; i++) {
|
||||
for (var j = 0; j < width; j++) {
|
||||
var idx = ((dontFlipY ? i : height - i - 1) * width + j) * 4;
|
||||
buffer.writeUInt8(pixels[idx + 1], offset++); // b
|
||||
buffer.writeUInt8(pixels[idx + 2], offset++); // g
|
||||
buffer.writeUInt8(pixels[idx + 3], offset++); // r
|
||||
buffer.writeUInt8(255, offset++); // a
|
||||
}
|
||||
}
|
||||
let offset = 18;
|
||||
for (let i = 0; i < height; i++) {
|
||||
for (let j = 0; j < width; j++) {
|
||||
const idx = ((dontFlipY ? i : height - i - 1) * width + j) * 4;
|
||||
buffer.writeUInt8(pixels[idx + 1], offset++); // b
|
||||
buffer.writeUInt8(pixels[idx + 2], offset++); // g
|
||||
buffer.writeUInt8(pixels[idx + 3], offset++); // r
|
||||
buffer.writeUInt8(255, offset++); // a
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export async function uploadCDNAsset(bucket, key, data, acl) {
|
||||
const awsPutParams = {
|
||||
Body: data,
|
||||
Key: key,
|
||||
Bucket: bucket,
|
||||
ACL: acl
|
||||
};
|
||||
const awsPutParams = {
|
||||
Body: data,
|
||||
Key: key,
|
||||
Bucket: bucket,
|
||||
ACL: acl
|
||||
};
|
||||
|
||||
await s3.putObject(awsPutParams).promise();
|
||||
await s3.putObject(awsPutParams).promise();
|
||||
}
|
||||
|
||||
export async function getFriends(pid) {
|
||||
return await client.getUserFriendPIDs({
|
||||
pid: pid
|
||||
}, {
|
||||
metadata: Metadata({
|
||||
'X-API-Key': api_key
|
||||
})
|
||||
})
|
||||
return await client.getUserFriendPIDs({
|
||||
pid: pid
|
||||
}, {
|
||||
metadata: Metadata({
|
||||
'X-API-Key': api_key
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export async function getFriendRequests(pid) {
|
||||
const requests = await client.getUserFriendRequestsIncoming({
|
||||
pid: pid
|
||||
}, {
|
||||
metadata: Metadata({
|
||||
'X-API-Key': api_key
|
||||
})
|
||||
});
|
||||
return requests.friendRequests;
|
||||
const requests = await client.getUserFriendRequestsIncoming({
|
||||
pid: pid
|
||||
}, {
|
||||
metadata: Metadata({
|
||||
'X-API-Key': api_key
|
||||
})
|
||||
});
|
||||
return requests.friendRequests;
|
||||
}
|
||||
|
||||
export function makeSafeQs(query: ParsedQs): SafeQs {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user