// Identity. Store your memories and mental belongings // Copyright (C) 2024 SofĂa Aritz // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. import app from "./app.js" import { ASSET_API_ENDPOINT, IDENTITY_API_LANDING_MESSAGE, LISTEN_PORT } from "./consts.js" import { contentFromSigned, verifySignature } from "./m2m.js"; import { startAuth } from "./auth.js"; import { randomUUID } from "node:crypto"; import cors from "@fastify/cors"; let auth = await startAuth(); app.register(cors, { origin: true, }) app.get("/", async () => { return IDENTITY_API_LANDING_MESSAGE; }); app.put("/m2m/asset", { async handler(request, reply) { if (!verifySignature(request.body)) { reply.statusCode(401); return; } let body = JSON.parse(contentFromSigned(request.body)); let user = await auth.findUserBySessionKey(body.session_key) user.assets.push(body.asset_id); await auth.updateUser(user.uid, user); app.log.info((await auth.findUserBySessionKey(body.session_key)).assets); }, }); app.post("/m2m/account", { async handler(request, reply) { if (!verifySignature(request.body)) { reply.statusCode(401); return; } let body = JSON.parse(contentFromSigned(request.body)); let user = await auth.findUserBySessionKey(body.session_key) user.password = undefined; user.entries = undefined; return user; }, }); app.get("/asset/endpoint", { async handler() { return ASSET_API_ENDPOINT } }) app.delete("/entry", { async handler(request, reply) { let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); let user = await auth.user(payload.uid); user.entries = user.entries.filter(v => v.id !== request.query.entry_id); await auth.updateUser(payload.uid, user); }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, query: { type: "object", properties: { entry_id: { type: "string" }, }, required: ["entry_id"], }, }, }) app.put("/entry", { async handler(request, reply) { let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); let user = await auth.user(payload.uid); request.body.entry.id = randomUUID().toString(); user.entries = [request.body.entry, ...user.entries]; await auth.updateUser(payload.uid, user); }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, body: { type: "object", properties: { entry: { type: "object" }, }, required: ["entry"], }, }, }) app.get("/entry/list", { async handler(request, reply) { if (request.query.offset < 0 || request.query.limit <= 0) { reply.status(400); return []; } let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); let user = await auth.user(payload.uid); return user.entries.slice(request.query.offset, request.query.offset + request.query.limit); }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, query: { type: "object", properties: { limit: { type: "number" }, offset: { type: "number" }, }, required: ["limit", "offset"], }, }, }) app.post("/auth/heirs", { async handler(request, reply) { let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); if (payload.uid == null) { reply.status(401); return; } let user = await auth.user(payload.uid); user.heirs = request.body; await auth.updateUser(payload.uid, user); }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, body: { type: "array", } } }) app.get("/auth/genkey", { async handler(request) { let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); let session_key = await auth.createSessionKey(payload.uid); return { session_key, }; }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, }, }); app.get("/auth/account", { async handler(request, reply) { let jwt = request.headers["authorization"].replace("Bearer", "").trim(); let { payload } = await auth.verifyJwt(jwt); if (payload.uid == null) { reply.status(401); return; } let user = await auth.user(payload.uid); user.password = undefined; user.entries = undefined; return user; }, schema: { headers: { type: "object", properties: { authorization: { type: "string" }, }, required: ["authorization"], }, }, }); app.post("/auth/login", { async handler(request, reply) { let user = await auth.findUserByEmail(request.body.email); if (user != null && user.password == request.body.password) { let token = await auth.createJwt(user.uid); return { token, }; } reply.code(400); return { error: "invalid credentials", }; }, schema: { body: { type: "object", properties: { email: { type: "string" }, password: { type: "string" }, }, }, required: ["email", "password"], }, }); app.post("/auth/register", { async handler(request, reply) { if (await auth.findUserByEmail(request.body.email) == null) { let user = await auth.addUser({ email: request.body.email, password: request.body.password, name: request.body.name, assets: [], limits: { assetCount: 5, }, entries: [], }); return { token: await auth.createJwt(user.uid) }; } reply.code(400); return { error: "invalid data", }; }, schema: { body: { type: "object", properties: { name: { type: "string" }, email: { type: "string" }, password: { type: "string" }, }, required: ["name", "email", "password"], }, }, }); app.listen({ port: LISTEN_PORT });