diff --git a/examples/nodejs/.DS_Store b/examples/nodejs/.DS_Store new file mode 100644 index 0000000..996e79d Binary files /dev/null and b/examples/nodejs/.DS_Store differ diff --git a/examples/nodejs/basic_auth/index.ts b/examples/nodejs/basic_auth/index.ts new file mode 100644 index 0000000..fc4afcc --- /dev/null +++ b/examples/nodejs/basic_auth/index.ts @@ -0,0 +1,57 @@ +import { Node } from "./node" +import { SessionStore } from "./session-store" +import { Memory } from "./session-store/memory" +import { randomBytes } from "tweetnacl"; +import bcrypt from "bcryptjs"; + +const salt = bcrypt.genSaltSync(10); +const session = new SessionStore(new Memory()); + +const users = [] + +const authenticate = (id: string, password: string) => { + return users.find(u => u.id === id) +} + +const main = async () => { + const node = await Node.start({ + addrs: [`127.0.0.1:9000`], + services: { + login: (ctx) => { + if (ctx.headers["params.id"] && ctx.headers["params.password"]) { + const authenticated = authenticate(ctx.headers["params.id"], ctx.headers["params.password"]); + if (authenticated && bcrypt.compareSync(ctx.headers["params.password"], authenticated.password)) { + const sid = Buffer.from(randomBytes(32)).toString('hex'); + session.create(sid, authenticated); + ctx.json(session.store.get(sid)); + } + else { + ctx.json({ + err: "Invalid credentials" + }); + } + } + else { + ctx.json({ + err: "Invalid credentials" + }); + } + }, + signup: (ctx) => { + if (ctx.headers["params.id"] && ctx.headers["params.password"]) { + users.push({ + id: ctx.headers["params.id"], + password: bcrypt.hashSync(ctx.headers["params.password"], salt) + }) + ctx.send('done'); + } + }, + logout: (ctx) => { + const sess = session.load(ctx.headers) + session.clear(sess.id) + } + }, + }); +}; + +main().catch((err) => console.error(err)); diff --git a/examples/nodejs/basic_auth/session-store/index.ts b/examples/nodejs/basic_auth/session-store/index.ts new file mode 100644 index 0000000..f772c8e --- /dev/null +++ b/examples/nodejs/basic_auth/session-store/index.ts @@ -0,0 +1,30 @@ +export class SessionStore { + store: any; + + constructor(store: any) { + this.store = store + } + + public load(headers: { [key:string]:string }) { + if(!headers.sessionId) { + return null + } else { + return this.store.get(headers.sessionId) + } + } + + public create(sessionId: string, payload: any) { + var maxAge = 86400; + var oneDay = 86400; + var now = new Date().getTime(); + var expiry = maxAge ? now + maxAge : now + oneDay; + this.store.set(sessionId, Object.assign({ + sid: sessionId, + expiry: expiry + }, payload)) + } + + public clear(sessionId: string) { + this.store.destroy(sessionId) + } +} \ No newline at end of file diff --git a/examples/nodejs/basic_auth/session-store/memory.ts b/examples/nodejs/basic_auth/session-store/memory.ts new file mode 100644 index 0000000..aefc6c8 --- /dev/null +++ b/examples/nodejs/basic_auth/session-store/memory.ts @@ -0,0 +1,62 @@ +export class Memory { + sessions: { [key: string]: any } + + constructor( + sessions: { [key: string]: any } = Object.create(null) + ) { + this.sessions = Object.create(null) + } + + public getSession(sessionId: string) { + var sess = this.sessions[sessionId] + + if (!sess) { + return + } + + // parse + sess = JSON.parse(sess) + + if (sess.cookie) { + var expires = typeof sess.cookie.expires === 'string' + ? new Date(sess.cookie.expires) + : sess.cookie.expires + + // destroy expired session + if (expires && expires <= Date.now()) { + delete this.sessions[sessionId] + return + } + } + + return sess + } + + public all() { + var sessionIds = Object.keys(this.sessions) + var sessions = Object.create(null) + + for (var i = 0; i < sessionIds.length; i++) { + var sessionId = sessionIds[i] + var session = this.getSession(sessionId) + + if (session) { + sessions[sessionId] = session; + } + } + + return sessions + } + + public set(sessionId: string, session: any) { + this.sessions[sessionId] = JSON.stringify(session) + } + + public get(sessionId: string) { + return this.getSession(sessionId) + } + + public destroy(sessionId: string) { + delete this.sessions[sessionId] + } +} \ No newline at end of file