Skip to content

Commit

Permalink
Merge pull request #62 from PretendoNetwork/dev
Browse files Browse the repository at this point in the history
Merge dev to master
  • Loading branch information
jonbarrow authored Feb 26, 2023
2 parents 886ea01 + 3954d75 commit 25c7a1a
Show file tree
Hide file tree
Showing 44 changed files with 4,866 additions and 2,106 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ typings/
# custom
sign.js
t.js
p.js
config.json
servers.json
certs
/cdn
/cdn
dump.rdb
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Account server

## What is this?
The account server is a replacement for several account-based services used by the WiiU and 3DS. It replaces the NNID api as well as NASC for the 3DS. It also contains a dedicated PNID api service for getting details of PNIDs outside of the consoles

## Setup
TODO
17 changes: 16 additions & 1 deletion docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/sh

# this doesnt check game server specific certs, only static file paths
files='config.json certs/nex/datastore/secret.key certs/access/secret.key certs/access/aes.key certs/access/private.pem certs/access/public.pem'
files='config.json'

for file in $files; do
if [ ! -f $file ]; then
Expand All @@ -10,4 +10,19 @@ for file in $files; do
fi
done

# check for keys
keys='certs/nex/datastore/secret.key certs/service/account/secret.key certs/service/account/aes.key certs/service/account/private.pem certs/service/account/public.pem'
for file in $keys; do
if [ ! -f "$file" ]; then
if [ x"${GENERATE_NEW_KEYS}" = "x" ]; then
echo "$PWD/$file file does not exist. Please mount and try again."
exit 1
else
echo "$PWD/$file file does not exist. Generating a temporary one"
node generate-keys.js nex datastore
node generate-keys.js account
fi
fi
done

exec node src/server.js
40 changes: 40 additions & 0 deletions example.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"http": {
"port": 7070
},
"mongoose": {
"connection_string": "mongodb://localhost:27017/database_name",
"options": {
"useNewUrlParser": true
}
},
"redis": {
"client": {
"url": "redis://localhost:6379"
}
},
"email": {
"host": "smtp.gmail.com",
"port": 587,
"secure": false,
"auth": {
"user": "username",
"pass": "password"
},
"from": "Company Name <[email protected]>"
},
"s3": {
"endpoint": "nyc3.digitaloceanspaces.com",
"key": "ACCESS_KEY",
"secret": "ACCESS_SECRET"
},
"hcaptcha": {
"secret": "0x0000000000000000000000000000000000000000"
},
"cdn": {
"base_url": "https://local-cdn.example.com",
"subdomain": "local-cdn",
"disk_path": "/home/jon/pretend-cdn"
},
"website_base": "https://example.com"
}
20 changes: 20 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
PN_ACT_PREFER_ENV_CONFIG=true # Load config from ENV instead of config.json
PN_ACT_CONFIG_HTTP_PORT=7070
PN_ACT_CONFIG_MONGO_CONNECTION_STRING=mongodb://localhost:27017/database_name
PN_ACT_CONFIG_MONGOOSE_OPTION_useNewUrlParser=true
PN_ACT_CONFIG_MONGOOSE_OPTION_useUnifiedTopology=true
PN_ACT_CONFIG_REDIS_URL=redis://localhost:6379
PN_ACT_CONFIG_EMAIL_HOST=smtp.gmail.com
PN_ACT_CONFIG_EMAIL_PORT=587
PN_ACT_CONFIG_EMAIL_SECURE=false
PN_ACT_CONFIG_EMAIL_USERNAME=username
PN_ACT_CONFIG_EMAIL_PASSWORD=password
PN_ACT_CONFIG_EMAIL_FROM=Company Name <[email protected]>
PN_ACT_CONFIG_S3_ENDPOINT=nyc3.digitaloceanspaces.com
PN_ACT_CONFIG_S3_ACCESS_KEY=ACCESS_KEY
PN_ACT_CONFIG_S3_ACCESS_SECRET=ACCESS_SECRET
PN_ACT_CONFIG_HCAPTCHA_SECRET=0x0000000000000000000000000000000000000000
PN_ACT_CONFIG_CDN_BASE_URL=https://local-cdn.example.com
PN_ACT_CONFIG_CDN_SUBDOMAIN=local-cdn
PN_ACT_CONFIG_CDN_DISK_PATH=/home/jon/pretend-cdn
PN_ACT_CONFIG_WEBSITE_BASE=https://example.com
175 changes: 116 additions & 59 deletions generate-keys.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,134 @@
const NodeRSA = require('node-rsa');
const crypto = require('crypto');
const fs = require('fs-extra');
const yesno = require('yesno');
const logger = require('./logger');
require('colors');

const args = process.argv.slice(2);
const ALLOWED_CHARS_REGEX = /[^a-zA-Z0-9_-]/g;

if (args.length < 1) {
usage();
return;
}

const [type, name] = args;

if (!['nex', 'service', 'access'].includes(type)) {
usage();
return;
}
async function main() {
const args = process.argv.slice(2);

if (type !== 'access' && (!name || name.trim() === '')) {
usage();
return;
}

let path;
if (args.length < 1) {
logger.error('Must pass in type and optional name');
usage();
return;
}

if (type === 'access') {
path = `${__dirname}/certs/${type}`;
} else {
path = `${__dirname}/certs/${type}/${name}`;
}
let [type, name] = args;

// Ensure the output directories exist
console.log('Creating output directories'.brightGreen);
fs.ensureDirSync(path);
type = type.toLowerCase().trim();

// Generate new AES key
console.log('Generating AES key'.brightGreen);
const aesKey = crypto.randomBytes(16);
if (name) {
name = name.toLowerCase().trim();

// Saving AES key
fs.writeFileSync(`${path}/aes.key`, aesKey.toString('hex'));
console.log(`Saved AES key to file ${path}/aes.key`.brightBlue);
if (ALLOWED_CHARS_REGEX.test(name)) {
logger.error(`Invalid name. Names must only contain [^a-zA-Z0-9_-]. Got ${name}`);
return;
}
}

const key = new NodeRSA({ b: 1024}, null, {
environment: 'browser',
encryptionScheme: {
'hash': 'sha256',
if (!['nex', 'service', 'account'].includes(type)) {
logger.error(`Invalid type. Expected nex, service, or account. Got ${type}`);
usage();
return;
}
});

// Generate new key pair
console.log('Generating RSA key pair'.brightGreen, '(this may take a while)'.yellow.bold);
key.generateKeyPair(1024);
if (type !== 'account' && (!name || name === '')) {
logger.error('If type is not account, a name MUST be passed');
usage();
return;
}

// Export the keys
console.log('Exporting public key'.brightGreen);
const publickKey = key.exportKey('public');
if (type === 'service' && name === 'account') {
logger.error('Cannot use service name \'account\'. Reserved');
usage();
return;
}

// Saving public key
fs.writeFileSync(`${path}/public.pem`, publickKey);
console.log(`Saved public key to file ${path}/public.pem`.brightBlue);
let path;

console.log('Exporting private key'.brightGreen);
const privatekKey = key.exportKey('private');
if (type === 'account') {
path = `${__dirname}/certs/service/account`;
} else {
path = `${__dirname}/certs/${type}/${name}`;
}

// Saving private key
fs.writeFileSync(`${path}/private.pem`, privatekKey);
console.log(`Saved public key to file ${path}/private.pem`.brightBlue);
if (fs.pathExistsSync(path)) {
const overwrite = await yesno({
question: 'Keys found for type name, overwrite existing keys?'
});

// Create HMAC secret key
console.log('Generating HMAC secret'.brightGreen);
const secret = crypto.randomBytes(16);
fs.writeFileSync(`${path}/secret.key`, secret.toString('hex'));
if (!overwrite) {
logger.info('Not overwriting existing keys. Exiting program');
return;
}
}

console.log(`Saved HMAC secret to file ${path}/secret.key`.brightBlue);
const publicKeyPath = `${path}/public.pem`;
const privateKeyPath = `${path}/private.pem`;
const aesKeyPath = `${path}/aes.key`;
const secretKeyPath = `${path}/secret.key`;

// Ensure the output directories exist
logger.info('Creating output directories...');
fs.ensureDirSync(path);
logger.success('Created output directories!');

const key = new NodeRSA({ b: 1024 }, null, {
environment: 'browser',
encryptionScheme: {
'hash': 'sha256',
}
});

// Generate new key pair
logger.info('Generating RSA key pair...');
logger.warn('(this may take a while)')
key.generateKeyPair(1024);
logger.success('Generated RSA key pair!');

// Export the keys
logger.info('Exporting public key...');
const publicKey = key.exportKey('public');
logger.success('Exported public key!');

// Saving public key
logger.info('Saving public key to disk...');
fs.writeFileSync(publicKeyPath, publicKey);
logger.success(`Saved public key to ${publicKeyPath}!`);

logger.info('Exporting private key...');
const privateKey = key.exportKey('private');
logger.success('Exported private key!');

// Saving private key
logger.info('Saving private key to disk...');
fs.writeFileSync(privateKeyPath, privateKey);
logger.success(`Saved private key to ${privateKeyPath}!`);

// Generate new AES key
logger.info('Generating AES key...');
const aesKey = crypto.randomBytes(16);
logger.success('Generated AES key!');

// Saving AES key
logger.info('Saving AES key to disk...');
fs.writeFileSync(aesKeyPath, aesKey.toString('hex'));
logger.success(`Saved AES key to ${aesKeyPath}!`);

// Create HMAC secret key
logger.info('Generating HMAC secret...');
const secret = crypto.randomBytes(16);
logger.success('Generated RSA key pair!');

logger.info('Saving HMAC secret to disk...');
fs.writeFileSync(secretKeyPath, secret.toString('hex'));
logger.success(`Saved HMAC secret to ${secretKeyPath}!`);

logger.success('Keys generated successfully');
}

// Display usage information
function usage() {
Expand All @@ -82,7 +137,9 @@ function usage() {
console.log('Types:');
console.log(' - nex');
console.log(' - service');
console.log(' - access');
console.log(' - account');

console.log('Name: Service or NEX server name. Not used in account type');
}

console.log('Name: service or nex server name. Not used in access type');
}
main().catch(logger.error);
32 changes: 32 additions & 0 deletions migrations/add-console-type-to-nex-account/migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const database = require('../../src/database');
const { NEXAccount } = require('../../src/models/nex-account');

database.connect().then(async function () {
const nexAccounts = await NEXAccount.find({});
const nexAccounts3DS = await NEXAccount.find({ device_type: '3ds' });
const nexAccountsWiiU = await NEXAccount.find({ device_type: 'wiiu' });

console.log('NEX accounts:', nexAccounts.length);
console.log('NEX accounts (3DS):', nexAccounts3DS.length);
console.log('NEX accounts (WiiU):', nexAccountsWiiU.length);

for (const nexAccount of nexAccounts) {
let deviceType = '';

if (nexAccount.owning_pid !== nexAccount.pid) {
// 3DS account
deviceType = '3ds';
} else {
// WiiU account
deviceType = 'wiiu';
}

nexAccount.device_type = deviceType;

await nexAccount.save();
}

console.log('Migrated accounts');

process.exit(0);
});
Loading

0 comments on commit 25c7a1a

Please sign in to comment.