You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.3 KiB
72 lines
2.3 KiB
import { createServer, type Server } from 'node:http';
|
|
|
|
/**
|
|
* Barebone in-memory key connector, just enough for the clients to enroll and unlock.
|
|
* Keys are stored per token subject; token validation is deliberately out of scope,
|
|
* this only exists to test the Vaultwarden and web client side of the flow.
|
|
*/
|
|
export function startMockKeyConnector(port: number) {
|
|
const keys = new Map<string, string>();
|
|
|
|
const server = createServer((req, res) => {
|
|
// The web client calls us cross-origin, with credentials
|
|
res.setHeader('Access-Control-Allow-Origin', req.headers['origin'] ?? '*');
|
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] ?? '*');
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
res.writeHead(204).end();
|
|
return;
|
|
}
|
|
|
|
if (req.url === '/alive') {
|
|
res.writeHead(200, { 'Content-Type': 'application/json' }).end(JSON.stringify({}));
|
|
return;
|
|
}
|
|
|
|
const sub = tokenSubject(req.headers['authorization']);
|
|
if (!sub) {
|
|
res.writeHead(401).end();
|
|
return;
|
|
}
|
|
|
|
if (req.url !== '/user-keys') {
|
|
res.writeHead(404).end();
|
|
return;
|
|
}
|
|
|
|
if (req.method === 'GET') {
|
|
if (!keys.has(sub)) {
|
|
res.writeHead(404).end();
|
|
return;
|
|
}
|
|
res.writeHead(200, { 'Content-Type': 'application/json' }).end(JSON.stringify({ key: keys.get(sub) }));
|
|
} else if (req.method === 'POST') {
|
|
let body = '';
|
|
req.on('data', (chunk) => body += chunk);
|
|
req.on('end', () => {
|
|
keys.set(sub, JSON.parse(body).key);
|
|
res.writeHead(200).end();
|
|
});
|
|
} else {
|
|
res.writeHead(405).end();
|
|
}
|
|
});
|
|
|
|
server.listen(port);
|
|
console.log(`Mock key connector running on port ${port}`);
|
|
|
|
return {
|
|
keys,
|
|
stop: () => server.close(),
|
|
};
|
|
}
|
|
|
|
function tokenSubject(header?: string): string | null {
|
|
try {
|
|
return JSON.parse(Buffer.from(header.replace(/^Bearer /, '').split('.')[1], 'base64url').toString()).sub;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|