mirror of
https://github.com/smogon/pokemon-showdown-loginserver.git
synced 2026-09-09 18:55:12 -05:00
Use RSA-SHA1 signing for validation instead
This commit is contained in:
@@ -14,26 +14,13 @@ import {Replays} from './replays';
|
||||
import {ActionError, QueryHandler, Server} from './server';
|
||||
import {Session} from './user';
|
||||
import {
|
||||
toID, updateserver, bash, time, escapeHTML, encrypt, decrypt, makeEncryptKey, randomString,
|
||||
toID, updateserver, bash, time, escapeHTML, signAsync,
|
||||
} from './utils';
|
||||
import * as tables from './tables';
|
||||
import {SQL} from './database';
|
||||
import IPTools from './ip-tools';
|
||||
|
||||
const OAUTH_TOKEN_TIME = 2 * 7 * 24 * 60 * 60 * 1000;
|
||||
const SMOGON_KEY = (() => {
|
||||
let keyData;
|
||||
if (!Config.smogonpath) return makeEncryptKey(randomString(), Math.random() + "");
|
||||
try {
|
||||
keyData = readFileSync(Config.smogonpath, 'utf-8');
|
||||
} catch {
|
||||
keyData = randomString() + "\n" + Math.random();
|
||||
writeFileSync(Config.smogonpath, keyData);
|
||||
}
|
||||
const [key, salt] = keyData.split('\n');
|
||||
return makeEncryptKey(key, salt);
|
||||
})();
|
||||
const SMOGON_VALIDATION_PREFIX = 'valid\n';
|
||||
|
||||
async function getOAuthClient(clientId?: string, origin?: string) {
|
||||
if (!clientId) throw new ActionError("No client_id provided.");
|
||||
@@ -919,7 +906,7 @@ export const actions: {[k: string]: QueryHandler} = {
|
||||
},
|
||||
|
||||
// sent by ps server
|
||||
'smogon/encrypt'(params) {
|
||||
async 'smogon/validate'(params) {
|
||||
if (this.getIp() !== Config.restartip) {
|
||||
throw new ActionError("Access denied.");
|
||||
}
|
||||
@@ -928,24 +915,9 @@ export const actions: {[k: string]: QueryHandler} = {
|
||||
throw new ActionError("Invalid PS username provided.");
|
||||
}
|
||||
return {
|
||||
encrypted_username: encrypt(SMOGON_KEY, SMOGON_VALIDATION_PREFIX + params.username),
|
||||
signed_username: await signAsync("RSA-SHA1", params.username, Config.privatekey),
|
||||
};
|
||||
},
|
||||
|
||||
// sent by smogon to validate given encrypted name
|
||||
'smogon/validate'(params) {
|
||||
if (this.getIp() !== Config.smogonip) {
|
||||
throw new ActionError("Access denied.");
|
||||
}
|
||||
if (!params.encrypted_name || !toID(params.encrypted_name)) {
|
||||
throw new ActionError("No encrypted name provided.");
|
||||
}
|
||||
const out = decrypt(SMOGON_KEY, decodeURIComponent(params.encrypted_name));
|
||||
if (!out || !out.startsWith(SMOGON_VALIDATION_PREFIX)) {
|
||||
return {decrypted_name: null};
|
||||
}
|
||||
return {decrypted_name: out.slice(SMOGON_VALIDATION_PREFIX.length)};
|
||||
},
|
||||
};
|
||||
|
||||
if (Config.actions) {
|
||||
|
||||
46
src/utils.ts
46
src/utils.ts
@@ -104,49 +104,3 @@ export function escapeHTML(str: string | number) {
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
const IV_LENGTH = 16;
|
||||
|
||||
const NONCE_LENGTH = 20;
|
||||
|
||||
export function encrypt(key: Buffer, text: string) {
|
||||
const nonce = crypto.randomBytes(NONCE_LENGTH);
|
||||
const iv = Buffer.alloc(IV_LENGTH);
|
||||
nonce.copy(iv);
|
||||
|
||||
const cipher = crypto.createCipheriv('aes-256-ctr', key, iv);
|
||||
const encrypted = cipher.update(text.toString());
|
||||
return Buffer.concat([nonce, encrypted, cipher.final()]).toString('base64');
|
||||
}
|
||||
|
||||
export function decrypt(key: Buffer, text: string) {
|
||||
const message = Buffer.from(text, 'base64');
|
||||
const iv = Buffer.alloc(IV_LENGTH);
|
||||
message.copy(iv, 0, 0, NONCE_LENGTH);
|
||||
const decipher = crypto.createDecipheriv('aes-256-ctr', key, iv);
|
||||
let decrypted = decipher.update(message.slice(NONCE_LENGTH));
|
||||
try {
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
return decrypted.toString();
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 32 chars - 256 bytes
|
||||
export function randomString(len = 32) {
|
||||
let chars = 'abcdefghijklmnopqrstuvwxyz';
|
||||
chars += chars.toUpperCase();
|
||||
chars += "1234567890";
|
||||
chars += "()-={}|!@#$%^&*?><:";
|
||||
|
||||
let key = "";
|
||||
for (let i = 0; i < len; i++) {
|
||||
key += chars[Math.round(Math.random() * chars.length)];
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export function makeEncryptKey(keyStr: string, saltStr: string) {
|
||||
return crypto.pbkdf2Sync(keyStr, saltStr, 10000, keyStr.length, 'sha512');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user