2024-03-12 20:02:23 -07:00
|
|
|
#!/usr/bin/env node
|
2024-03-13 13:00:27 -07:00
|
|
|
/**
|
|
|
|
* A test NeoPass server! This is a very lean, hacky implementation, designed
|
|
|
|
* to just see the basic OAuth interactions Work At All.
|
|
|
|
*
|
2024-03-14 18:11:40 -07:00
|
|
|
* 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!
|
2024-03-13 13:00:27 -07:00
|
|
|
*
|
2024-03-14 18:11:40 -07:00
|
|
|
* 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.
|
2024-03-13 13:00:27 -07:00
|
|
|
*/
|
2024-03-12 20:02:23 -07:00
|
|
|
|
Use local-only HTTPS certs for the development neopass-server
I'm starting to work with the OpenID Connect stuff in NeoPass, and the
library I'm using for discovery doesn't seem to want to do it over a
plain `http://` connection. (I dug into the source files, and it just
actually is hardcoded to only work with HTTPS, as far as I can tell?)
So, I've added logic to `neopass-server` to try to make an HTTPS
certificate with the `mkcert` utility (if installed), which is a tool
that installs a root certificate authority on your local machine, then
helps you create certificates via that authority that will work only on
your local machine.
I think I'll also be able to remove the "main" server in front of the
backing server, because the library I'm using now will be able to
"discover" the auth and token endpoints, so it won't matter that our
local one uses different URLs than live NeoPass does? We'll find out!
I also remove `neopass-server` from the `Procfile`, because I think
it's a bit rude to have it auto-try to run `mkcert`. We could like,
make the process just a no-op in that case? But I think I'd prefer to
just run `neopass-server` by hand when I want it, for simplicity.
2024-03-14 17:58:29 -07:00
|
|
|
const fs = require("node:fs/promises");
|
|
|
|
const pathLib = require("node:path");
|
|
|
|
const { spawn } = require("node:child_process");
|
2024-03-13 13:00:27 -07:00
|
|
|
const urlLib = require("node:url");
|
Use local-only HTTPS certs for the development neopass-server
I'm starting to work with the OpenID Connect stuff in NeoPass, and the
library I'm using for discovery doesn't seem to want to do it over a
plain `http://` connection. (I dug into the source files, and it just
actually is hardcoded to only work with HTTPS, as far as I can tell?)
So, I've added logic to `neopass-server` to try to make an HTTPS
certificate with the `mkcert` utility (if installed), which is a tool
that installs a root certificate authority on your local machine, then
helps you create certificates via that authority that will work only on
your local machine.
I think I'll also be able to remove the "main" server in front of the
backing server, because the library I'm using now will be able to
"discover" the auth and token endpoints, so it won't matter that our
local one uses different URLs than live NeoPass does? We'll find out!
I also remove `neopass-server` from the `Procfile`, because I think
it's a bit rude to have it auto-try to run `mkcert`. We could like,
make the process just a no-op in that case? But I think I'd prefer to
just run `neopass-server` by hand when I want it, for simplicity.
2024-03-14 17:58:29 -07:00
|
|
|
|
2024-03-12 20:02:23 -07:00
|
|
|
const { OAuth2Server } = require("oauth2-mock-server");
|
2024-03-13 13:00:27 -07:00
|
|
|
const express = require("express");
|
2024-03-12 20:02:23 -07:00
|
|
|
|
2024-03-14 19:11:06 -07:00
|
|
|
// This is the Neopets username and email we'll report back to DTI when you
|
|
|
|
// authenticate through here.
|
|
|
|
const USERNAME = "test";
|
|
|
|
const EMAIL = "theneopetsteam@neopets.com";
|
2024-03-14 18:19:45 -07:00
|
|
|
|
Use local-only HTTPS certs for the development neopass-server
I'm starting to work with the OpenID Connect stuff in NeoPass, and the
library I'm using for discovery doesn't seem to want to do it over a
plain `http://` connection. (I dug into the source files, and it just
actually is hardcoded to only work with HTTPS, as far as I can tell?)
So, I've added logic to `neopass-server` to try to make an HTTPS
certificate with the `mkcert` utility (if installed), which is a tool
that installs a root certificate authority on your local machine, then
helps you create certificates via that authority that will work only on
your local machine.
I think I'll also be able to remove the "main" server in front of the
backing server, because the library I'm using now will be able to
"discover" the auth and token endpoints, so it won't matter that our
local one uses different URLs than live NeoPass does? We'll find out!
I also remove `neopass-server` from the `Procfile`, because I think
it's a bit rude to have it auto-try to run `mkcert`. We could like,
make the process just a no-op in that case? But I think I'd prefer to
just run `neopass-server` by hand when I want it, for simplicity.
2024-03-14 17:58:29 -07:00
|
|
|
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.",
|
|
|
|
);
|
|
|
|
|
2024-03-14 18:19:45 -07:00
|
|
|
const mkcertProc = spawn(
|
|
|
|
"mkcert",
|
|
|
|
["-cert-file", certPath, "-key-file", keyPath, "localhost"],
|
|
|
|
{ stdio: ["ignore", process.stdout, process.stderr] },
|
|
|
|
);
|
Use local-only HTTPS certs for the development neopass-server
I'm starting to work with the OpenID Connect stuff in NeoPass, and the
library I'm using for discovery doesn't seem to want to do it over a
plain `http://` connection. (I dug into the source files, and it just
actually is hardcoded to only work with HTTPS, as far as I can tell?)
So, I've added logic to `neopass-server` to try to make an HTTPS
certificate with the `mkcert` utility (if installed), which is a tool
that installs a root certificate authority on your local machine, then
helps you create certificates via that authority that will work only on
your local machine.
I think I'll also be able to remove the "main" server in front of the
backing server, because the library I'm using now will be able to
"discover" the auth and token endpoints, so it won't matter that our
local one uses different URLs than live NeoPass does? We'll find out!
I also remove `neopass-server` from the `Procfile`, because I think
it's a bit rude to have it auto-try to run `mkcert`. We could like,
make the process just a no-op in that case? But I think I'd prefer to
just run `neopass-server` by hand when I want it, for simplicity.
2024-03-14 17:58:29 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-14 18:11:40 -07:00
|
|
|
async function startServer(port) {
|
2024-03-14 18:19:45 -07:00
|
|
|
const server = new OAuth2Server(keyPath, certPath);
|
2024-03-12 20:02:23 -07:00
|
|
|
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",
|
|
|
|
});
|
|
|
|
|
2024-03-14 19:11:06 -07:00
|
|
|
server.service.on("beforeTokenSigning", (token) => {
|
2024-03-14 18:19:45 -07:00
|
|
|
token.payload.sub = USERNAME;
|
|
|
|
});
|
|
|
|
|
2024-03-14 19:11:06 -07:00
|
|
|
server.service.on("beforeUserinfo", (userInfoResponse) => {
|
|
|
|
userInfoResponse.body.email = EMAIL;
|
|
|
|
});
|
|
|
|
|
2024-03-13 13:00:27 -07:00
|
|
|
await server.start(port, "localhost");
|
2024-03-14 18:11:40 -07:00
|
|
|
console.log(`Started NeoPass development server at: ${server.issuer.url}`);
|
2024-03-13 13:00:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
async function main() {
|
Use local-only HTTPS certs for the development neopass-server
I'm starting to work with the OpenID Connect stuff in NeoPass, and the
library I'm using for discovery doesn't seem to want to do it over a
plain `http://` connection. (I dug into the source files, and it just
actually is hardcoded to only work with HTTPS, as far as I can tell?)
So, I've added logic to `neopass-server` to try to make an HTTPS
certificate with the `mkcert` utility (if installed), which is a tool
that installs a root certificate authority on your local machine, then
helps you create certificates via that authority that will work only on
your local machine.
I think I'll also be able to remove the "main" server in front of the
backing server, because the library I'm using now will be able to
"discover" the auth and token endpoints, so it won't matter that our
local one uses different URLs than live NeoPass does? We'll find out!
I also remove `neopass-server` from the `Procfile`, because I think
it's a bit rude to have it auto-try to run `mkcert`. We could like,
make the process just a no-op in that case? But I think I'd prefer to
just run `neopass-server` by hand when I want it, for simplicity.
2024-03-14 17:58:29 -07:00
|
|
|
await ensureCertsExist();
|
2024-03-14 18:11:40 -07:00
|
|
|
await startServer(8585);
|
2024-03-12 20:02:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
main().catch((error) => {
|
|
|
|
console.error(error);
|
|
|
|
});
|