Skip to content

Commit d31ddcc

Browse files
committed
Add actions to support linking PS and Smogon accounts
1 parent 75b2885 commit d31ddcc

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

config/config-example.js

+6
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ exports.watchconfig = true;
151151
*/
152152
exports.restartip = null;
153153

154+
/**
155+
* An IP to allow Smogon acc-linking requests from.
156+
* @type {null | string}
157+
*/
158+
exports.smogonip = null;
159+
154160
/**
155161
* Custom actions for your loginserver.
156162
* @type {{[k: string]: import('../src/server').QueryHandler} | null}

src/actions.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ import {Ladder} from './ladder';
1313
import {Replays} from './replays';
1414
import {ActionError, QueryHandler, Server} from './server';
1515
import {Session} from './user';
16-
import {toID, updateserver, bash, time, escapeHTML} from './utils';
16+
import {
17+
toID, updateserver, bash, time, escapeHTML, encrypt, decrypt, makeEncryptKey,
18+
} from './utils';
1719
import * as tables from './tables';
1820
import {SQL} from './database';
1921
import IPTools from './ip-tools';
2022

2123
const OAUTH_TOKEN_TIME = 2 * 7 * 24 * 60 * 60 * 1000;
24+
const SMOGON_KEY = makeEncryptKey();
2225

2326
async function getOAuthClient(clientId?: string, origin?: string) {
2427
if (!clientId) throw new ActionError("No client_id provided.");
@@ -902,6 +905,29 @@ export const actions: {[k: string]: QueryHandler} = {
902905
}
903906
return {password: pw};
904907
},
908+
909+
// sent by ps server
910+
'smogon/encrypt'(params) {
911+
if (this.getIp() !== Config.restartip) {
912+
throw new ActionError("Access denied.");
913+
}
914+
params.username = toID(params.username);
915+
if (!params.username) {
916+
throw new ActionError("Invalid PS username provided.");
917+
}
918+
return {encrypted_username: encrypt(SMOGON_KEY, params.username)};
919+
},
920+
921+
// sent by smogon to validate given encrypted name
922+
'smogon/validate'(params) {
923+
if (this.getIp() !== Config.smogonip) {
924+
throw new ActionError("Access denied.");
925+
}
926+
if (!params.encrypted_name || !toID(params.encrypted_name)) {
927+
throw new ActionError("No encrypted name provided.");
928+
}
929+
return {decrypted_name: decrypt(SMOGON_KEY, params.encrypted_name)};
930+
},
905931
};
906932

907933
if (Config.actions) {

src/utils.ts

+43
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,46 @@ export function escapeHTML(str: string | number) {
104104
.replace(/"/g, '"')
105105
.replace(/'/g, ''');
106106
}
107+
108+
const IV_LENGTH = 16;
109+
110+
const NONCE_LENGTH = 20;
111+
112+
export function encrypt(key: Buffer, text: string) {
113+
const nonce = crypto.randomBytes(NONCE_LENGTH);
114+
const iv = Buffer.alloc(IV_LENGTH);
115+
nonce.copy(iv);
116+
117+
const cipher = crypto.createCipheriv('aes-256-ctr', key, iv);
118+
const encrypted = cipher.update(text.toString());
119+
return Buffer.concat([nonce, encrypted, cipher.final()]).toString('base64');
120+
}
121+
122+
export function decrypt(key: Buffer, text: string) {
123+
const message = Buffer.from(text, 'base64');
124+
const iv = Buffer.alloc(IV_LENGTH);
125+
message.copy(iv, 0, 0, NONCE_LENGTH);
126+
const decipher = crypto.createDecipheriv('aes-256-ctr', key, iv);
127+
let decrypted = decipher.update(message.slice(NONCE_LENGTH));
128+
try {
129+
decrypted = Buffer.concat([decrypted, decipher.final()]);
130+
return decrypted.toString();
131+
} catch (err) {
132+
return null;
133+
}
134+
}
135+
136+
// 32 chars - 256 bytes
137+
export function makeEncryptKey(len = 32) {
138+
let chars = 'abcdefghijklmnopqrstuvwxyz';
139+
chars += chars.toUpperCase();
140+
chars += "1234567890";
141+
chars += "()-={}|!@#$%^&*?><:";
142+
143+
let key = "";
144+
for (let i = 0; i < len; i++) {
145+
key += chars[Math.round(Math.random() * chars.length)];
146+
}
147+
148+
return crypto.pbkdf2Sync(key, Math.random() + "", 10000, len, 'sha512');
149+
}

0 commit comments

Comments
 (0)