Merge pull request #347 from suprstarrd/fix/remove-connection-route
Some checks failed
Build and Publish Docker Image / Build and Publish Docker Image (amd64) (push) Has been cancelled
Build and Publish Docker Image / Build and Publish Docker Image (arm64) (push) Has been cancelled

fix: remove legacy connections route
This commit is contained in:
mrjvs
2026-08-06 14:33:41 +02:00
committed by GitHub
9 changed files with 33 additions and 262 deletions

114
package-lock.json generated
View File

@@ -12,7 +12,7 @@
"@aws-sdk/client-s3": "^3.657.0",
"@aws-sdk/client-ses": "^3.515.0",
"@inquirer/prompts": "^7.2.0",
"@pretendonetwork/grpc": "^2.5.2",
"@pretendonetwork/grpc": "^2.5.4",
"bcrypt": "^5.0.0",
"buffer-crc32": "^0.2.13",
"colors": "^1.4.0",
@@ -32,7 +32,6 @@
"image-pixels": "^1.1.1",
"ip2location-nodejs": "^9.6.3",
"is-valid-hostname": "^1.0.2",
"joi": "^17.8.3",
"mii-js": "github:PretendoNetwork/mii-js#f1741e1f82771dd7c753fd408230373d33caa184",
"moment": "^2.29.4",
"mongoose": "^7.0.0",
@@ -525,9 +524,9 @@
"license": "MIT"
},
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -606,9 +605,9 @@
"license": "MIT"
},
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -778,21 +777,6 @@
"node": ">=12"
}
},
"node_modules/@hapi/hoek": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
"license": "BSD-3-Clause"
},
"node_modules/@hapi/topo": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
"integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
"license": "BSD-3-Clause",
"dependencies": {
"@hapi/hoek": "^9.0.0"
}
},
"node_modules/@hcaptcha/types": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.2.0.tgz",
@@ -1685,9 +1669,9 @@
}
},
"node_modules/@pretendonetwork/grpc": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/@pretendonetwork/grpc/-/grpc-2.5.3.tgz",
"integrity": "sha512-4Vn46SZRTcaI9DS11Es+9/HqywwFHkhjC/yOJwRPebG8lbzlxy2iA03KVhFoxqFKPxepV4Jo76CzOHQ8zd9bcQ==",
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@pretendonetwork/grpc/-/grpc-2.5.4.tgz",
"integrity": "sha512-spjg6sOSP8z+9T9vqR9RM5guJb7UHYQlFBfb6p6WxpaYHsXlmVIRPeQlR7NTkgpNzARV/4QVpqerBbtLDvN4oA==",
"license": "AGPL-3.0-only",
"dependencies": {
"@bufbuild/protobuf": "^2.2.2",
@@ -1831,27 +1815,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
"integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==",
"license": "BSD-3-Clause",
"dependencies": {
"@hapi/hoek": "^9.0.0"
}
},
"node_modules/@sideway/formula": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
"license": "BSD-3-Clause"
},
"node_modules/@sideway/pinpoint": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
"license": "BSD-3-Clause"
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
@@ -3409,16 +3372,16 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
"integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
"node": "20 || >=22"
}
},
"node_modules/brfs": {
@@ -3881,9 +3844,9 @@
"license": "MIT"
},
"node_modules/copyfiles/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4996,9 +4959,9 @@
"license": "MIT"
},
"node_modules/eslint-plugin-import/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5080,9 +5043,9 @@
"license": "MIT"
},
"node_modules/eslint-plugin-react/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5151,9 +5114,9 @@
"license": "MIT"
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5470,9 +5433,9 @@
"license": "MIT"
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz",
"integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==",
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -5914,9 +5877,9 @@
"license": "MIT"
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -6945,19 +6908,6 @@
"node": ">=10"
}
},
"node_modules/joi": {
"version": "17.13.4",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.13.4.tgz",
"integrity": "sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==",
"license": "BSD-3-Clause",
"dependencies": {
"@hapi/hoek": "^9.3.0",
"@hapi/topo": "^5.1.0",
"@sideway/address": "^4.1.5",
"@sideway/formula": "^3.0.1",
"@sideway/pinpoint": "^2.0.0"
}
},
"node_modules/jpeg-js": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz",

View File

@@ -28,7 +28,7 @@
"@aws-sdk/client-s3": "^3.657.0",
"@aws-sdk/client-ses": "^3.515.0",
"@inquirer/prompts": "^7.2.0",
"@pretendonetwork/grpc": "^2.5.2",
"@pretendonetwork/grpc": "^2.5.4",
"bcrypt": "^5.0.0",
"buffer-crc32": "^0.2.13",
"colors": "^1.4.0",
@@ -48,7 +48,6 @@
"image-pixels": "^1.1.1",
"ip2location-nodejs": "^9.6.3",
"is-valid-hostname": "^1.0.2",
"joi": "^17.8.3",
"mii-js": "github:PretendoNetwork/mii-js#f1741e1f82771dd7c753fd408230373d33caa184",
"moment": "^2.29.4",
"mongoose": "^7.0.0",

View File

@@ -1,7 +1,6 @@
import crypto from 'node:crypto';
import mongoose from 'mongoose';
import bcrypt from 'bcrypt';
import joi from 'joi';
import { nintendoPasswordHash } from '@/util';
import { OAuthToken } from '@/models/oauth-token';
import { PNID } from '@/models/pnid';
@@ -14,18 +13,10 @@ import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
import type { IDeviceAttribute } from '@/types/mongoose/device-attribute';
import type { HydratedServerDocument } from '@/types/mongoose/server';
import type { PNIDProfile } from '@/types/services/nnas/pnid-profile';
import type { ConnectionData } from '@/types/services/api/connection-data';
import type { ConnectionResponse } from '@/types/services/api/connection-response';
import type { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
const connection_string = config.mongoose.connection_string;
const options = config.mongoose.options;
// TODO - Extend this later with more settings
const discordConnectionSchema = joi.object({
id: joi.string()
});
const accessModeOrder: Record<string, string[]> = {
prod: ['prod'],
test: ['test', 'prod'],
@@ -304,55 +295,6 @@ export async function getServerByClientID(clientID: string, accessMode: string):
return null;
}
export async function addPNIDConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise<ConnectionResponse | undefined> {
if (type === 'discord') {
return await addPNIDConnectionDiscord(pnid, data);
}
}
export async function addPNIDConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise<ConnectionResponse> {
const valid = discordConnectionSchema.validate(data);
if (valid.error) {
return {
app: 'api',
status: 400,
error: 'Invalid or missing connection data'
};
}
await PNID.updateOne({ pid: pnid.pid }, {
$set: {
'connections.discord.id': data.id
}
});
return {
app: 'api',
status: 200
};
}
export async function removePNIDConnection(pnid: HydratedPNIDDocument, type: string): Promise<ConnectionResponse | undefined> {
// * Add more connections later?
if (type === 'discord') {
return await removePNIDConnectionDiscord(pnid);
}
}
export async function removePNIDConnectionDiscord(pnid: HydratedPNIDDocument): Promise<ConnectionResponse> {
await PNID.updateOne({ pid: pnid.pid }, {
$set: {
'connections.discord.id': ''
}
});
return {
app: 'api',
status: 200
};
}
export async function checkMarkedDeletions(): Promise<void> {
const pnids = await PNID.find({
marked_for_deletion: true,

View File

@@ -16,7 +16,6 @@ api.options('*', cors());
// * Setup routes
LOG_INFO('[USER API] Applying imported routes');
api.use('/v1/connections', V1.CONNECTIONS);
api.use('/v1/email', V1.EMAIL);
api.use('/v1/forgot-password', V1.FORGOT_PASSWORD);
api.use('/v1/login', V1.LOGIN);

View File

@@ -1,4 +1,3 @@
import connections_v1 from '@/services/api/routes/v1/connections';
import email_v1 from '@/services/api/routes/v1/email';
import forgotPassword_v1 from '@/services/api/routes/v1/forgotPassword';
import login_v1 from '@/services/api/routes/v1/login';
@@ -7,7 +6,6 @@ import resetPassword_v1 from '@/services/api/routes/v1/resetPassword';
import user_v1 from '@/services/api/routes/v1/user';
export const V1 = {
CONNECTIONS: connections_v1,
EMAIL: email_v1,
FORGOT_PASSWORD: forgotPassword_v1,
LOGIN: login_v1,

View File

@@ -1,105 +0,0 @@
import express from 'express';
import { addPNIDConnection, removePNIDConnection } from '@/database';
const router = express.Router();
const VALID_CONNECTION_TYPES = [
'discord'
];
/**
* [POST]
* Implementation of for: https://api.pretendo.cc/v1/connections/add/TYPE
* Description: Adds an account connection to the users PNID
*/
router.post('/add/:type', async (request: express.Request, response: express.Response): Promise<void> => {
const data = request.body?.data;
const pnid = request.pnid;
const type = request.params.type;
if (!pnid) {
response.status(400).json({
app: 'api',
status: 400,
error: 'Invalid or missing access token'
});
return;
}
if (!data) {
response.status(400).json({
app: 'api',
status: 400,
error: 'Invalid or missing connection data'
});
return;
}
if (!VALID_CONNECTION_TYPES.includes(type)) {
response.status(400).json({
app: 'api',
status: 400,
error: 'Invalid or missing connection type'
});
return;
}
let result = await addPNIDConnection(pnid, data, type);
if (!result) {
result = {
app: 'api',
status: 500,
error: 'Unknown server error'
};
}
response.status(result.status || 500).json(result);
});
/**
* [DELETE]
* Implementation of for: https://api.pretendo.cc/v1/connections/remove/TYPE
* Description: Removes an account connection from the users PNID
*/
router.delete('/remove/:type', async (request: express.Request, response: express.Response): Promise<void> => {
const pnid = request.pnid;
const type = request.params.type;
if (!pnid) {
response.status(400).json({
app: 'api',
status: 400,
error: 'Invalid or missing access token'
});
return;
}
if (!VALID_CONNECTION_TYPES.includes(type)) {
response.status(400).json({
app: 'api',
status: 400,
error: 'Invalid or missing connection type'
});
return;
}
let result = await removePNIDConnection(pnid, type);
if (!result) {
result = {
app: 'api',
status: 500,
error: 'Unknown server error'
};
}
response.status(result.status).json(result);
});
export default router;

View File

@@ -1,4 +0,0 @@
import type { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
// TODO - This will be a union of all ConnectionData types when more connections are added
export type ConnectionData = DiscordConnectionData;

View File

@@ -1,5 +0,0 @@
export interface ConnectionResponse {
app: string;
status: number;
error?: string;
}

View File

@@ -1,3 +0,0 @@
export interface DiscordConnectionData {
id: string;
}