Emi Matchu
31a11a04fa
Okay, `sub` seems to be a pretty standard place for user identifiers. Let's start with that assumption! I override the `oauth2-mock-server`'s default of `johndoe` with `theneopetsteam`, just to be cute :3
106 lines
4.3 KiB
JavaScript
Executable file
106 lines
4.3 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
/**
|
|
* A test NeoPass server! This is a very lean, hacky implementation, designed
|
|
* to just see the basic OAuth interactions Work At All.
|
|
*
|
|
* This server is an `oauth2-mock-server` instance that's easy to spin up and
|
|
* have perform OAuth for us. We give it a hardcoded development-only key, and
|
|
* it just auto-grants permissions!
|
|
*
|
|
* It slightly differs from the NeoPass spec, in that it uses different paths
|
|
* for its endpoints, but that's okay: DTI will use OpenID's "discovery"
|
|
* feature to discover those endpoints via a single well-known path, without
|
|
* needing them hardcoded.
|
|
*/
|
|
|
|
const fs = require("node:fs/promises");
|
|
const pathLib = require("node:path");
|
|
const { spawn } = require("node:child_process");
|
|
const urlLib = require("node:url");
|
|
|
|
const { OAuth2Server } = require("oauth2-mock-server");
|
|
const express = require("express");
|
|
|
|
// This is the Neopets username we'll report back to DTI when you authenticate
|
|
// through here.
|
|
const USERNAME = "theneopetsteam";
|
|
|
|
const certPath = pathLib.join(__dirname, "..", "tmp", "localhost.pem");
|
|
const keyPath = pathLib.join(__dirname, "..", "tmp", "localhost-key.pem");
|
|
|
|
async function fileExists(path) {
|
|
try {
|
|
await fs.stat(path);
|
|
} catch (error) {
|
|
if (error.code === "ENOENT") {
|
|
return false;
|
|
}
|
|
throw error;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async function ensureCertsExist() {
|
|
if (!(await fileExists(certPath)) || !(await fileExists(keyPath))) {
|
|
console.log(
|
|
"Using mkcert to create localhost.pem and localhost-key.pem in " +
|
|
"the Rails tmp dir, to serve over HTTPS.",
|
|
);
|
|
|
|
const mkcertProc = spawn(
|
|
"mkcert",
|
|
["-cert-file", certPath, "-key-file", keyPath, "localhost"],
|
|
{ stdio: ["ignore", process.stdout, process.stderr] },
|
|
);
|
|
|
|
// Wait for the process to finish, raising an error if it fails.
|
|
await new Promise((resolve, reject) => {
|
|
mkcertProc.on("close", (code) => {
|
|
if (code === 0) {
|
|
resolve();
|
|
} else {
|
|
reject(new Error(`mkcert returned status ${code}`));
|
|
}
|
|
});
|
|
mkcertProc.on("error", (error) => {
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
async function startServer(port) {
|
|
const server = new OAuth2Server(keyPath, certPath);
|
|
await server.issuer.keys.add({
|
|
// A key we generated for the NeoPass test server. It's okay for its
|
|
// "secret" info to be here, because it's for development only!
|
|
kid: "neopass-server-DEVLOPMENT-ONLY-NOT-FOR-PRODUCTION",
|
|
p: "50btwsJlPbGLUFnCSBZzddyMX_oRQ8nz4lMrpAd4umPLqMUmS0NbBZNf6DI7s8PkRUxtV8KdvZh3OYWavFnbk55GDG4Y_J_wA4XlHU3d5KIfSNaIdbtVp4CFOq1lovho4sYX_26vcGgYb2Azeg7nz_gDpqNmIdJdKuZxzsrboK8",
|
|
kty: "RSA",
|
|
q: "xha0i9_lbOMQhmmni02Dtpocil26GI7W8xbOFyOvceBCRNf-XOA_-W_Xk9ItJRHnAWM1TML36PN0l864d4QAXbBo64FHu2cjdFKnXJNliJaPcOPAMQB_D8GSylU1gTwSpP_vVe8t232LeF1oBwbOoBIS-6NsOpLmL8Sezv6Fpac",
|
|
d: "WSUNeEd_EyaELK7wqT6GJJK_RfYjaE5h6USe9rD9cd_tQE2PaZWXMyZ4OCk5Z5hdG2ryZY7NYsOI2CPs8HCFBqMoKd0z0A0EgB8Dq2fe_-t5Rm0Zq1ZnI5tnBcZeQmw0hDT98Wg00FA53SSUqfnOgI_VuLvquM6f18_XQOKRRfTcwh1a4teDAH0g0s8FVOS5DANtg71mTdq5fEkWmQMD3qKC6SNrx3WXXHezDs0MWdeFqn9Dg7gssSqB7PnqB-hlC_fHnu4gm9nDqPTMzsJC2i8d3adm0AeORRCulGLe7hU-_TgTbZzgIYCgOK_asaewW-6Qk9qFj-J4djBaKIee-Q",
|
|
e: "AQAB",
|
|
use: "sig",
|
|
qi: "WNiwCcAk2x7e0KvuupL2DNU-JUjLEF9Onee5T9u9ihbgGSDIyP04_96TzCIK3wsY6lct64oOo0Er-z5cf_5eOBPD3n0eEL-JuKIgn0mEKrazJOnGQzlyeZPzk4dUO2J7D42ObopfYsoBIcJx-Y_43a6WORDMGSVCiURmKavTHUU",
|
|
dp: "p1_wj-Npq3VDElpzPQJqeuCrAoaSWhHcm21_hs0VdSbl6_UJ2qwbQnS-kudPx7A8El7WPw4MZHrjxdBIBImvXCzOGw7OrHz_ET2ka0nADUe7BlakGTgDLB7ZzHZSuNe36G5eTbCH7PyYunnPp0UERMEDu2RDdLSuUm7F7FdpDOc",
|
|
alg: "RS256",
|
|
dq: "purLCHKKKM7NRfYRsFiI_H2wPwfroHX8uqokz2rKk_Kc5NX9CNYOEmokBfO9BtenCIxIhX5k2G8NeD5BQrSAenIEdy5g-5FVVtevH1s023vDMyU29hOs_eHnh4d1poiwTUk8q_T3d1S7CZnr5r_drRSN2m1C7biLLwVHrLTceVE",
|
|
n: "svVfGU4NGcfBCmQiIOW5uzg5SAN2CWSIQSstnhqZoCdjy5OoKpKVR8O9TbDvxixrvkFyAav90Q0Xse8iFTcjfCKuqINYiuYMXhCvfBlc_DVVOQca9pMpN03LaDofd5Ll4_BFTtt1nSPahwWU7xDM-Bkkh_TcS2qS4N2xbpEGi0q0ZkrJN4WyiDBC2k9WbK-YHr4Rj4JKypFVSeBIrjxVPmlPzgfqlLGGIB0l92SnJDXDMlkWcCCTyLgqSBM04nkxGDSykq_ei76qCdRd7b10wMBaoS9DeBThAyHpur2LoPdH3gxbcwoWExi-jPlNP1LdKVZD8b95OY3CRyMAAMGdKQ",
|
|
});
|
|
|
|
server.service.on("beforeTokenSigning", (token, req) => {
|
|
token.payload.sub = USERNAME;
|
|
});
|
|
|
|
await server.start(port, "localhost");
|
|
console.log(`Started NeoPass development server at: ${server.issuer.url}`);
|
|
}
|
|
|
|
async function main() {
|
|
await ensureCertsExist();
|
|
await startServer(8585);
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
});
|