304 lines
8.1 KiB
JavaScript
304 lines
8.1 KiB
JavaScript
// 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 });
|