diff --git a/.gitignore b/.gitignore index e0d81ee..57ebd55 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ package-lock.json # production /build +/dist # misc .DS_Store diff --git a/dist/server/api.js b/dist/server/api.js deleted file mode 100644 index 7729969..0000000 --- a/dist/server/api.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_router_1 = __importDefault(require("koa-router")); -const hub_helpers_1 = require("./hub-helpers"); -/** - * Start API Routes - * - * All prefixed with `/api/` - */ -const api = new koa_router_1.default({ - prefix: '/api' -}); -/** - * Create a REST API endpoint at /api/auth - * - * This endpoint will provide authorization for _any_ user. - */ -api.get('/userauth', (ctx, next) => __awaiter(void 0, void 0, void 0, function* () { - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAPISig(); - /** Include the token in the auth payload */ - const credentials = Object.assign(Object.assign({}, auth), { key: process.env.USER_API_KEY }); - /** Return the auth in a JSON object */ - ctx.body = credentials; - yield next(); -})); -api.get('/appauth', (ctx, next) => __awaiter(void 0, void 0, void 0, function* () { - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAppAPISig(); - /** Include the token in the auth payload */ - const credentials = Object.assign(Object.assign({}, auth), { key: process.env.ORG_API_KEY }); - /** Return the auth in a JSON object */ - ctx.body = credentials; - yield next(); -})); -api.get('/enckey', (ctx, next) => __awaiter(void 0, void 0, void 0, function* () { - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAPISig(); - /** Include the token in the auth payload */ - const encKeyCredentials = Object.assign(Object.assign({}, auth), { key: process.env.USER_API_KEY }); - /** Return the auth in a JSON object */ - ctx.body = encKeyCredentials; - yield next(); -})); -exports.default = api; -//# sourceMappingURL=api.js.map \ No newline at end of file diff --git a/dist/server/api.js.map b/dist/server/api.js.map deleted file mode 100644 index f9c5f52..0000000 --- a/dist/server/api.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAEA,4DAAgC;AAIhC,+CAAwD;AAGxD;;;;GAIG;AACH,MAAM,GAAG,GAAG,IAAI,oBAAM,CAAwB;IAC5C,MAAM,EAAE,MAAM;CACf,CAAC,CAAC;AAEH;;;;GAIG;AACH,GAAG,CAAC,GAAG,CAAE,WAAW,EAAE,CAAO,GAAY,EAAE,IAAwB,EAAE,EAAE;IACrE,yCAAyC;IACzC,MAAM,IAAI,GAAG,MAAM,uBAAS,EAAE,CAAA;IAE9B,4CAA4C;IAC5C,MAAM,WAAW,mCACZ,IAAI,KACP,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,GAC9B,CAAC;IAEF,uCAAuC;IACvC,GAAG,CAAC,IAAI,GAAG,WAAW,CAAA;IAEtB,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAA,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAE,UAAU,EAAE,CAAO,GAAY,EAAE,IAAwB,EAAE,EAAE;IACpE,yCAAyC;IACzC,MAAM,IAAI,GAAG,MAAM,0BAAY,EAAE,CAAA;IAEjC,4CAA4C;IAC5C,MAAM,WAAW,mCACZ,IAAI,KACP,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,GAC7B,CAAC;IAEF,uCAAuC;IACvC,GAAG,CAAC,IAAI,GAAG,WAAW,CAAA;IAEtB,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAA,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAE,SAAS,EAAE,CAAO,GAAY,EAAE,IAAwB,EAAE,EAAE;IACjE,yCAAyC;IACzC,MAAM,IAAI,GAAG,MAAM,uBAAS,EAAE,CAAA;IAE9B,4CAA4C;IAC5C,MAAM,iBAAiB,mCAClB,IAAI,KACP,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,GAC9B,CAAC;IAEF,uCAAuC;IACvC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAA;IAE5B,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAA,CAAC,CAAC;AAEL,kBAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/dist/server/appwss.js b/dist/server/appwss.js deleted file mode 100644 index 171e365..0000000 --- a/dist/server/appwss.js +++ /dev/null @@ -1,127 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_route_1 = __importDefault(require("koa-route")); -const emittery_1 = __importDefault(require("emittery")); -const hub_helpers_1 = require("./hub-helpers"); -/** - * In a real system you might have a real user-singup flow - * Here, we just stub in a basic user "database". - * Users are added by their Public Key. - * Users will only be added if they prove they hold the private key. - * Proof is done using the Hub's built in token challenge API. - */ -const AppDB = {}; -/** - * This login includes a more thorough identity verification step. - * - * It leverages the Hub's public key verification via challenge. - * The challenge is issued server-side by fulfilled here, client-side. - * This has several benefits. - * - User private key never needs to leave the user/client. - * - The server will leverage the Hub verification in the process of user registration. - * - The server can maintain a record of: user public key and user token in list of users. - */ -const appwss = koa_route_1.default.all('/ws/appauth', (ctx) => { - /** Emittery allows us to wait for the challenge response event */ - const emitter = new emittery_1.default(); - ctx.websocket.on('message', (msg) => __awaiter(void 0, void 0, void 0, function* () { - try { - /** All messages from client contain {type: string} */ - const data = JSON.parse(msg.toString()); - switch (data.type) { - case 'token': { - /** A new token request will contain the user's public key */ - if (!data.pubkey) { - throw new Error('missing pubkey'); - } - /** - * Init new Hub API Client - * - * see ./hub.ts - */ - const db = yield hub_helpers_1.newAppClientDB(); - /** Request a token from the Hub based on the user public key */ - const token = yield db.getTokenChallenge(data.pubkey, - /** The callback passes the challenge back to the client */ - (challenge) => { - return new Promise((resolve, reject) => { - /** Pass the challenge to the client */ - ctx.websocket.send(JSON.stringify({ - type: 'challenge', - value: Buffer.from(challenge).toJSON(), - })); - /** Wait for the challenge event from our event emitter */ - emitter.on('challenge', (sig) => { - /** Resolve the promise with the challenge response */ - resolve(Buffer.from(sig)); - }); - /** Give client a reasonable timeout to respond to the challenge */ - setTimeout(() => { - reject(); - }, 10000); - }); - }); - /** - * The challenge was successfully completed by the client - */ - /** - * The user has verified they own the pubkey. - * Add or update the user in the user database - */ - const app = { - pubkey: data.pub, - lastSeen: new Date(), - }; - AppDB[data.pub] = app; - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAppAPISig(); - /** Include the token in the auth payload */ - const payload = Object.assign(Object.assign({}, auth), { token: token, key: process.env.ORG_API_KEY }); - const returnData = { - type: 'token', - value: payload - }; - /** Return the result to the client */ - ctx.websocket.send(JSON.stringify(returnData)); - ctx.websocket.close(); - break; - } - /** The second type is a challenge response */ - case 'challenge': { - /** A new challenge response will contain a signature */ - if (!data.sig) { - throw new Error('missing signature (sig)'); - } - /** - * If the timeout hasn't passed there is a waiting promise. - * Emit the challenge signature for the waiting listener above. - * */ - yield emitter.emit('challenge', data.sig); - break; - } - } - } - catch (error) { - /** Notify our client of any errors */ - ctx.websocket.send(JSON.stringify({ - type: 'error', - value: error.message, - })); - ctx.websocket.close(); - } - })); -}); -exports.default = appwss; -//# sourceMappingURL=appwss.js.map \ No newline at end of file diff --git a/dist/server/appwss.js.map b/dist/server/appwss.js.map deleted file mode 100644 index b3603a2..0000000 --- a/dist/server/appwss.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"appwss.js","sourceRoot":"","sources":["../../src/server/appwss.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/server/client/index.html b/dist/server/client/index.html deleted file mode 100644 index 6e23335..0000000 --- a/dist/server/client/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - VP Backend - - -

Keep Alive.

- - \ No newline at end of file diff --git a/dist/server/enckey.js b/dist/server/enckey.js deleted file mode 100644 index 18bfd3b..0000000 --- a/dist/server/enckey.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_route_1 = __importDefault(require("koa-route")); -const enckey = koa_route_1.default.all('/ws/enckey', (ctx) => { - /** Emittery allows us to wait for the challenge response event */ - ctx.websocket.on('message', (msg) => __awaiter(void 0, void 0, void 0, function* () { - try { - /** All messages from client contain {type: string} */ - const data = JSON.parse(msg.toString()); - switch (data.type) { - case 'enckey': - { - /** A new token request will contain the user's public key */ - if (!data.pubkey) { - throw new Error('missing pubkey'); - } - /** Include the token in the auth payload */ - const payload = { - pubkey: data.pub, - enckey: process.env.ENC_KEY - }; - const returnData = { - type: 'enckey', - value: payload - }; - /** Return the result to the client */ - ctx.websocket.send(JSON.stringify(returnData)); - break; - } - ctx.websocket.close(); - } - } - catch (error) { - /** Notify our client of any errors */ - ctx.websocket.send(JSON.stringify({ - type: 'error', - value: error.message, - })); - ctx.websocket.close(); - } - })); -}); -exports.default = enckey; -//# sourceMappingURL=enckey.js.map \ No newline at end of file diff --git a/dist/server/enckey.js.map b/dist/server/enckey.js.map deleted file mode 100644 index e6d38e8..0000000 --- a/dist/server/enckey.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"enckey.js","sourceRoot":"","sources":["../../src/server/enckey.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,0DAA8B;AAO9B,MAAM,MAAM,GAAG,mBAAK,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE;IAC7C,kEAAkE;IAElE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,CAAO,GAAG,EAAE,EAAE;QACxC,IAAI;YACF,sDAAsD;YACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxC,QAAQ,IAAI,CAAC,IAAI,EAAE;gBACjB,KAAK,QAAQ;oBAAE;wBACb,6DAA6D;wBAC7D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;4BAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAA;yBAAE;wBAEvD,4CAA4C;wBAC5C,MAAM,OAAO,GAAW;4BACtB,MAAM,EAAE,IAAI,CAAC,GAAG;4BAChB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;yBAC5B,CAAC;wBAEF,MAAM,UAAU,GAAG;4BACf,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAE,OAAO;yBACjB,CAAA;wBAED,sCAAsC;wBACtC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAA;wBAE9C,MAAM;qBACP;oBACD,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;aACtB;SACF;QAAC,OAAO,KAAK,EAAE;YACd,sCAAsC;YACtC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;gBAChC,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,KAAK,CAAC,OAAO;aACrB,CAAC,CAAC,CAAA;YACH,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;SACtB;IACH,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/dist/server/hub-helpers.js b/dist/server/hub-helpers.js deleted file mode 100644 index b5821f2..0000000 --- a/dist/server/hub-helpers.js +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.newAppClientDB = exports.newClientDB = exports.getAppAPISig = exports.getAPISig = void 0; -const hub_1 = require("@textile/hub"); -/** - * getAPISig uses helper function to create a new sig - * - * seconds (300) time until the sig expires - */ -exports.getAPISig = (seconds = 300) => __awaiter(void 0, void 0, void 0, function* () { - const expiration = new Date(Date.now() + 1000 * seconds); - return yield hub_1.createAPISig(process.env.USER_API_SECRET, expiration); -}); -exports.getAppAPISig = (seconds = 300) => __awaiter(void 0, void 0, void 0, function* () { - const expiration = new Date(Date.now() + 1000 * seconds); - return yield hub_1.createAPISig(process.env.ORG_API_SECRET, expiration); -}); -/** - * newClientDB creates a Client (remote DB) connection to the Hub - * - * A Hub connection is required to use the getToken API - */ -exports.newClientDB = () => __awaiter(void 0, void 0, void 0, function* () { - const API = process.env.API || undefined; - const db = yield hub_1.Client.withKeyInfo({ - key: process.env.USER_API_KEY, - secret: process.env.USER_API_SECRET - }, API); - return db; -}); -exports.newAppClientDB = () => __awaiter(void 0, void 0, void 0, function* () { - const API = process.env.API || undefined; - const db = yield hub_1.Client.withKeyInfo({ - key: process.env.ORG_API_KEY, - secret: process.env.ORG_API_SECRET - }, API); - return db; -}); -//# sourceMappingURL=hub-helpers.js.map \ No newline at end of file diff --git a/dist/server/hub-helpers.js.map b/dist/server/hub-helpers.js.map deleted file mode 100644 index 7179407..0000000 --- a/dist/server/hub-helpers.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"hub-helpers.js","sourceRoot":"","sources":["../../src/server/hub-helpers.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,sCAAkD;AAElD;;;;GAIG;AACU,QAAA,SAAS,GAAG,CAAO,UAAkB,GAAG,EAAE,EAAE;IACvD,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,CAAA;IACxD,OAAO,MAAM,kBAAY,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;AACpE,CAAC,CAAA,CAAA;AAEY,QAAA,YAAY,GAAG,CAAO,UAAkB,GAAG,EAAE,EAAE;IAC1D,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,CAAA;IACxD,OAAO,MAAM,kBAAY,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAA;AACnE,CAAC,CAAA,CAAA;AAGD;;;;GAIG;AACU,QAAA,WAAW,GAAG,GAAS,EAAE;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,SAAS,CAAA;IACxC,MAAM,EAAE,GAAG,MAAM,YAAM,CAAC,WAAW,CAAC;QAClC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QAC7B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;KACpC,EAAE,GAAG,CAAC,CAAA;IACP,OAAO,EAAE,CAAC;AACZ,CAAC,CAAA,CAAA;AAEY,QAAA,cAAc,GAAG,GAAS,EAAE;IACvC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,SAAS,CAAA;IACxC,MAAM,EAAE,GAAG,MAAM,YAAM,CAAC,WAAW,CAAC;QAClC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;QAC5B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;KACnC,EAAE,GAAG,CAAC,CAAA;IACP,OAAO,EAAE,CAAC;AACZ,CAAC,CAAA,CAAA"} \ No newline at end of file diff --git a/dist/server/index.js b/dist/server/index.js deleted file mode 100644 index 63980a2..0000000 --- a/dist/server/index.js +++ /dev/null @@ -1,72 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_1 = __importDefault(require("koa")); -const koa_router_1 = __importDefault(require("koa-router")); -const koa_logger_1 = __importDefault(require("koa-logger")); -const koa_json_1 = __importDefault(require("koa-json")); -const koa_bodyparser_1 = __importDefault(require("koa-bodyparser")); -const koa_static_1 = __importDefault(require("koa-static")); -const koa_websocket_1 = __importDefault(require("koa-websocket")); -const fs_1 = require("fs"); -const dotenv_1 = __importDefault(require("dotenv")); -const userwss_1 = __importDefault(require("./userwss")); -const appwss_1 = __importDefault(require("./appwss")); -const enckey_1 = __importDefault(require("./enckey")); -const api_1 = __importDefault(require("./api")); -dotenv_1.default.config(); -if (!process.env.USER_API_KEY || - !process.env.USER_API_SECRET) { - process.exit(1); -} -const PORT = parseInt(process.env.PORT, 10) || 3001; -const app = koa_websocket_1.default(new koa_1.default()); -/** Middlewares */ -app.use(koa_json_1.default()); -app.use(koa_logger_1.default()); -app.use(koa_bodyparser_1.default()); -/* Not safe in production */ -//app.use(cors()); -app.use(koa_static_1.default(__dirname + '/client')); -/** - * Start HTTP Routes - */ -const router = new koa_router_1.default(); -app.use(router.routes()).use(router.allowedMethods()); -/** - * Serve index.html - */ -router.get('/', (ctx, next) => __awaiter(void 0, void 0, void 0, function* () { - ctx.type = 'text/html; charset=utf-8'; - ctx.body = fs_1.createReadStream(__dirname + '/client/index.html'); - yield next(); -})); -/** - * Create Rest endpoint for server-side token issue - * - * See ./api.ts - */ -app.use(api_1.default.routes()); -app.use(api_1.default.allowedMethods()); -/** - * Create Websocket endpoint for client-side token challenge - * - * See ./wss.ts - */ -app.ws.use(userwss_1.default); -app.ws.use(appwss_1.default); -app.ws.use(enckey_1.default); -/** Start the server! */ -app.listen(PORT, () => console.log("Server started.")); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/server/index.js.map b/dist/server/index.js.map deleted file mode 100644 index 5cc594f..0000000 --- a/dist/server/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,8CAAsB;AACtB,4DAAgC;AAChC,4DAAgC;AAChC,wDAA4B;AAC5B,oEAAwC;AACxC,4DAA+B;AAC/B,kEAAuC;AAIvC,2BAAsC;AACtC,oDAA4B;AAE5B,wDAAgC;AAChC,sDAA8B;AAC9B,sDAA8B;AAC9B,gDAAwB;AAExB,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,IACI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY;IACzB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAC9B;IACA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CACjB;AAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC;AAEpD,MAAM,GAAG,GAAG,uBAAU,CAAC,IAAI,aAAG,EAAE,CAAC,CAAC;AAElC,kBAAkB;AAClB,GAAG,CAAC,GAAG,CAAE,kBAAI,EAAE,CAAE,CAAC;AAClB,GAAG,CAAC,GAAG,CAAE,oBAAM,EAAE,CAAE,CAAC;AACpB,GAAG,CAAC,GAAG,CAAE,wBAAU,EAAE,CAAE,CAAC;AAExB,4BAA4B;AAC5B,kBAAkB;AAElB,GAAG,CAAC,GAAG,CAAC,oBAAK,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC;AAEtC;;GAEG;AACH,MAAM,MAAM,GAAG,IAAI,oBAAM,EAAyB,CAAC;AACnD,GAAG,CAAC,GAAG,CAAE,MAAM,CAAC,MAAM,EAAE,CAAE,CAAC,GAAG,CAAE,MAAM,CAAC,cAAc,EAAE,CAAE,CAAC;AAE1D;;GAEG;AACH,MAAM,CAAC,GAAG,CAAE,GAAG,EAAE,CAAO,GAAY,EAAE,IAAwB,EAAE,EAAE;IAC9D,GAAG,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACtC,GAAG,CAAC,IAAI,GAAG,qBAAgB,CAAC,SAAS,GAAG,oBAAoB,CAAC,CAAC;IAC9D,MAAM,IAAI,EAAE,CAAC;AACjB,CAAC,CAAA,CAAC,CAAC;AAEH;;;;GAIG;AACH,GAAG,CAAC,GAAG,CAAE,aAAG,CAAC,MAAM,EAAE,CAAE,CAAC;AACxB,GAAG,CAAC,GAAG,CAAE,aAAG,CAAC,cAAc,EAAE,CAAE,CAAC;AAEhC;;;;GAIG;AACH,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,iBAAO,CAAC,CAAC;AACpB,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,gBAAM,CAAC,CAAC;AACnB,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,gBAAM,CAAC,CAAC;AAEnB,wBAAwB;AACxB,GAAG,CAAC,MAAM,CAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAE,iBAAiB,CAAE,CAAE,CAAC"} \ No newline at end of file diff --git a/dist/server/userwss.js b/dist/server/userwss.js deleted file mode 100644 index 16e7694..0000000 --- a/dist/server/userwss.js +++ /dev/null @@ -1,128 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_route_1 = __importDefault(require("koa-route")); -const emittery_1 = __importDefault(require("emittery")); -const hub_helpers_1 = require("./hub-helpers"); -/** - * In a real system you might have a real user-singup flow - * Here, we just stub in a basic user "database". - * Users are added by their Public Key. - * Users will only be added if they prove they hold the private key. - * Proof is done using the Hub's built in token challenge API. - */ -const UserDB = {}; -/** - * This login includes a more thorough identity verification step. - * - * It leverages the Hub's public key verification via challenge. - * The challenge is issued server-side by fulfilled here, client-side. - * This has several benefits. - * - User private key never needs to leave the user/client. - * - The server will leverage the Hub verification in the process of user registration. - * - The server can maintain a record of: user public key and user token in list of users. - */ -const userwss = koa_route_1.default.all('/ws/userauth', (ctx) => { - /** Emittery allows us to wait for the challenge response event */ - const emitter = new emittery_1.default(); - ctx.websocket.on('message', (msg) => __awaiter(void 0, void 0, void 0, function* () { - try { - /** All messages from client contain {type: string} */ - const data = JSON.parse(msg.toString()); - switch (data.type) { - case 'token': { - /** A new token request will contain the user's public key */ - if (!data.pubkey) { - throw new Error('missing pubkey'); - } - /** - * Init new Hub API Client - * - * see ./hub.ts - */ - const db = yield hub_helpers_1.newClientDB(); - /** Request a token from the Hub based on the user public key */ - const token = yield db.getTokenChallenge(data.pubkey, - /** The callback passes the challenge back to the client */ - (challenge) => { - return new Promise((resolve, reject) => { - /** Pass the challenge to the client */ - ctx.websocket.send(JSON.stringify({ - type: 'challenge', - value: Buffer.from(challenge).toJSON(), - })); - /** Wait for the challenge event from our event emitter */ - emitter.on('challenge', (sig) => { - console.log('sig ', sig); - /** Resolve the promise with the challenge response */ - resolve(Buffer.from(sig)); - }); - /** Give client a reasonable timeout to respond to the challenge */ - setTimeout(() => { - reject(); - }, 10000); - }); - }); - /** - * The challenge was successfully completed by the client - */ - /** - * The user has verified they own the pubkey. - * Add or update the user in the user database - */ - const user = { - pubkey: data.pub, - lastSeen: new Date(), - }; - UserDB[data.pub] = user; - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAPISig(); - /** Include the token in the auth payload */ - const payload = Object.assign(Object.assign({}, auth), { token: token, key: process.env.USER_API_KEY }); - const returnData = { - type: 'token', - value: payload - }; - /** Return the result to the client */ - ctx.websocket.send(JSON.stringify(returnData)); - ctx.websocket.close(); - break; - } - /** The second type is a challenge response */ - case 'challenge': { - /** A new challenge response will contain a signature */ - if (!data.sig) { - throw new Error('missing signature (sig)'); - } - /** - * If the timeout hasn't passed there is a waiting promise. - * Emit the challenge signature for the waiting listener above. - * */ - yield emitter.emit('challenge', data.sig); - break; - } - } - } - catch (error) { - /** Notify our client of any errors */ - ctx.websocket.send(JSON.stringify({ - type: 'error', - value: error.message, - })); - ctx.websocket.close(); - } - })); -}); -exports.default = userwss; -//# sourceMappingURL=userwss.js.map \ No newline at end of file diff --git a/dist/server/userwss.js.map b/dist/server/userwss.js.map deleted file mode 100644 index 30549de..0000000 --- a/dist/server/userwss.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"userwss.js","sourceRoot":"","sources":["../../src/server/userwss.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/server/wss.js b/dist/server/wss.js deleted file mode 100644 index 6e1ee86..0000000 --- a/dist/server/wss.js +++ /dev/null @@ -1,125 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const koa_route_1 = __importDefault(require("koa-route")); -const emittery_1 = __importDefault(require("emittery")); -const hub_helpers_1 = require("./hub-helpers"); -/** - * In a real system you might have a real user-singup flow - * Here, we just stub in a basic user "database". - * Users are added by their Public Key. - * Users will only be added if they prove they hold the private key. - * Proof is done using the Hub's built in token challenge API. - */ -const UserDB = {}; -/** - * This login includes a more thorough identity verification step. - * - * It leverages the Hub's public key verification via challenge. - * The challenge is issued server-side by fulfilled here, client-side. - * This has several benefits. - * - User private key never needs to leave the user/client. - * - The server will leverage the Hub verification in the process of user registration. - * - The server can maintain a record of: user public key and user token in list of users. - */ -const wss = koa_route_1.default.all('/ws/userauth', (ctx) => { - /** Emittery allows us to wait for the challenge response event */ - const emitter = new emittery_1.default(); - ctx.websocket.on('message', (msg) => __awaiter(void 0, void 0, void 0, function* () { - try { - /** All messages from client contain {type: string} */ - const data = JSON.parse(msg); - switch (data.type) { - /** The first type is a new token request */ - case 'token': { - /** A new token request will contain the user's public key */ - if (!data.pubkey) { - throw new Error('missing pubkey'); - } - /** - * Init new Hub API Client - * - * see ./hub.ts - */ - const db = yield hub_helpers_1.newClientDB(); - /** Request a token from the Hub based on the user public key */ - const token = yield db.getTokenChallenge(data.pubkey, - /** The callback passes the challenge back to the client */ - (challenge) => { - return new Promise((resolve, reject) => { - /** Pass the challenge to the client */ - ctx.websocket.send(JSON.stringify({ - type: 'challenge', - value: Buffer.from(challenge).toJSON(), - })); - /** Wait for the challenge event from our event emitter */ - emitter.on('challenge', (sig) => { - /** Resolve the promise with the challenge response */ - resolve(Buffer.from(sig)); - }); - /** Give client a reasonable timeout to respond to the challenge */ - setTimeout(() => { - reject(); - }, 1500); - }); - }); - /** - * The challenge was successfully completed by the client - */ - /** - * The user has verified they own the pubkey. - * Add or update the user in the user database - */ - const user = { - pubkey: data.pub, - lastSeen: new Date(), - }; - UserDB[data.pub] = user; - /** Get API authorization for the user */ - const auth = yield hub_helpers_1.getAPISig(); - /** Include the token in the auth payload */ - const payload = Object.assign(Object.assign({}, auth), { token: token, key: process.env.USER_API_KEY }); - /** Return the result to the client */ - ctx.websocket.send(JSON.stringify({ - type: 'token', - value: payload, - })); - break; - } - /** The second type is a challenge response */ - case 'challenge': { - /** A new challenge response will contain a signature */ - if (!data.sig) { - throw new Error('missing signature (sig)'); - } - /** - * If the timeout hasn't passed there is a waiting promise. - * Emit the challenge signature for the waiting listener above. - * */ - yield emitter.emit('challenge', data.sig); - break; - } - } - } - catch (error) { - /** Notify our client of any errors */ - ctx.websocket.send(JSON.stringify({ - type: 'error', - value: error.message, - })); - } - })); -}); -exports.default = wss; -//# sourceMappingURL=wss.js.map \ No newline at end of file diff --git a/dist/server/wss.js.map b/dist/server/wss.js.map deleted file mode 100644 index 3b2b260..0000000 --- a/dist/server/wss.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"wss.js","sourceRoot":"","sources":["../../src/server/wss.ts"],"names":[],"mappings":"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"} \ No newline at end of file