import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts"; import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts"; import { auth, body, rest, schema } from "../server/decorators.ts"; import HttpError from "../server/HttpError.ts"; import User from "../models/User.ts"; import AppRouter from "./AppRouter.ts"; import jwt from "../server/decorators/jwt.ts"; import JWT, { JWTPayload } from "../utils/JWT.ts"; import { now } from "../utils/utils.ts"; export interface SignupRequest { username: string; password: string; } export interface LoginRequest { username: string; password: string; } export default class UserRouter extends AppRouter { @rest('GET', '/') async get(@schema('string') username: string) { const res = await this.users.findOne({ username }); if (res === undefined) throw new HttpError('User not found.'); return { username: res.username }; } @rest('GET', '/self') async self(@jwt(self => self.salt, true) @auth() auth: JWTPayload) { if (auth === undefined) throw new HttpError('You are not logged in.'); const res = await this.users.findOne({ username: auth.name }); if (res === undefined) throw new HttpError('User not found.'); return { username: res.username }; } @rest('POST', '/signup') async signup( @schema({ username: 'string', password: 'string', }) @body() body: SignupRequest ) { if (await this.users.countDocuments({ username: body.username }) > 0) { throw new HttpError('User with the same username already exists.'); } const password = await bcrypt.hash(body.password, this.salt); await this.users.insertOne({ username: body.username, password: password, images: [], }); return {}; } @rest('POST', '/login') async login( @schema({ username: 'string', password: 'string' }) @body() body: LoginRequest ) { const res = await this.users.findOne({ username: body.username }); if (!res) throw new HttpError('Incorrect username or password.'); const hashed = await bcrypt.hash(body.password, this.salt); if (res.password !== hashed) throw new HttpError('Incorrect username or password.'); const time = now(); return JWT.encode({ iat: time, exp: time + 3600 * 12, name: res.username, }, this.salt); } public constructor(private salt: string, private users: Collection) { super(); users.createIndexes({ indexes: [ { key: { username: 1 }, name: 'Username Index' } ] }); } }