add api keys

This commit is contained in:
Emily
2024-09-08 15:51:03 +02:00
parent 73739dde9d
commit be45448288
11 changed files with 325 additions and 5 deletions

View File

@@ -0,0 +1,47 @@
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import { ApiSettingsModel, TApiSettings } from "@schema/ApiSettingsSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { ProjectModel } from "@schema/ProjectSchema";
import crypto from 'crypto';
function generateApiKey() {
return 'lit_' + crypto.randomBytes(6).toString('hex');
}
export default defineEventHandler(async event => {
const body = await readBody(event);
if (body.name.length == 0) return setResponseStatus(event, 400, 'name is required');
if (body.name.length < 3) return setResponseStatus(event, 400, 'name too short');
if (body.name.length > 32) return setResponseStatus(event, 400, 'name too long');
const userData = getRequestUser(event);
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id });
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id;
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const key = generateApiKey();
const keyNumbers = await ApiSettingsModel.countDocuments({ project_id });
if (keyNumbers >= 5) return setResponseStatus(event, 400, 'Api key limit reached');
const newApiSettings = await ApiSettingsModel.create({ project_id, apiKey: key, apiName: body.name, created_at: Date.now(), usage: 0 });
return newApiSettings.toJSON();
});

View File

@@ -0,0 +1,28 @@
import { ApiSettingsModel } from "@schema/ApiSettingsSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { ProjectModel } from "@schema/ProjectSchema";
export default defineEventHandler(async event => {
const body = await readBody(event);
const userData = getRequestUser(event);
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id });
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id;
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const deletation = await ApiSettingsModel.deleteOne({ _id: body.api_id });
return { ok: deletation.acknowledged };
});

View File

@@ -0,0 +1,33 @@
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import { ApiSettingsModel, TApiSettings } from "@schema/ApiSettingsSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { ProjectModel } from "@schema/ProjectSchema";
function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings {
return { ...apiSettings, apiKey: apiSettings.apiKey.substring(0, 6) + '******' }
}
export default defineEventHandler(async event => {
const userData = getRequestUser(event);
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id });
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id;
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const apiKeys = await ApiSettingsModel.find({ project_id }, { project_id: 0 })
return apiKeys.map(e => cryptApiKeyName(e.toJSON())) as TApiSettings[];
});

View File

@@ -21,6 +21,8 @@ export default defineEventHandler(async event => {
}
const { name } = await readBody(event);
if (name.length == 0) return setResponseStatus(event, 400, 'name is required');
project.name = name;
await project.save();

View File

@@ -8,6 +8,7 @@ import { ProjectModel, TProject } from "@schema/ProjectSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { VisitModel } from '@schema/metrics/VisitSchema';
import { EventModel } from '@schema/metrics/EventSchema';
import { ProjectSnapshotModel } from '@schema/ProjectSnapshot';
type PDF_Data = {
@@ -114,8 +115,11 @@ export default defineEventHandler(async event => {
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
const fromHeader = getHeader(event, 'x-from');
const toHeader = getHeader(event, 'x-from');
const from = fromHeader;
const to = toHeader;
const eventsCount = await EventModel.countDocuments({ project_id: project._id });
const visitsCount = await VisitModel.countDocuments({ project_id: project._id });

View File

@@ -0,0 +1,44 @@
import { ApiSettingsModel } from '@schema/ApiSettingsSchema';
import { EventModel } from '@schema/metrics/EventSchema';
export default defineEventHandler(async event => {
const { row, from, to, limit } = getQuery(event);
const authorization = getHeader(event, 'Authorization');
if (!authorization) return setResponseStatus(event, 403, 'Authorization is required');
const [type, token] = authorization.split(' ');
if (type != 'Bearer') return setResponseStatus(event, 401, 'Malformed authorization');
const apiSettings = await ApiSettingsModel.findOne({ apiKey: token });
if (!apiSettings) return setResponseStatus(event, 401, 'ApiKey not valid');
if (!row) return setResponseStatus(event, 400, 'row is required');
const rows: string[] = Array.isArray(row) ? row as string[] : [row as string];
const projection: any = {};
for (const row of rows) {
projection[row] = 1;
}
const limitNumber = parseInt((limit as string));
const limitValue = isNaN(limitNumber) ? 100 : limitNumber;
const visits = await EventModel.find({
project_id: apiSettings.project_id,
created_at: {
$gte: from || new Date(2023, 0),
$lte: to || new Date(3000, 0)
}
}, { _id: 0, ...projection }, { limit: limitValue });
return visits.map(e => e.toJSON());
});

View File

@@ -0,0 +1,44 @@
import { ApiSettingsModel } from '@schema/ApiSettingsSchema';
import { VisitModel } from '@schema/metrics/VisitSchema';
export default defineEventHandler(async event => {
const { row, from, to, limit } = getQuery(event);
const authorization = getHeader(event, 'Authorization');
if (!authorization) return setResponseStatus(event, 403, 'Authorization is required');
const [type, token] = authorization.split(' ');
if (type != 'Bearer') return setResponseStatus(event, 401, 'Malformed authorization');
const apiSettings = await ApiSettingsModel.findOne({ apiKey: token });
if (!apiSettings) return setResponseStatus(event, 401, 'ApiKey not valid');
if (!row) return setResponseStatus(event, 400, 'row is required');
const rows: string[] = Array.isArray(row) ? row as string[] : [row as string];
const projection: any = {};
for (const row of rows) {
projection[row] = 1;
}
const limitNumber = parseInt((limit as string));
const limitValue = isNaN(limitNumber) ? 100 : limitNumber;
const visits = await VisitModel.find({
project_id: apiSettings.project_id,
created_at: {
$gte: from || new Date(2023, 0),
$lte: to || new Date(3000, 0)
}
}, { _id: 0, ...projection }, { limit: limitValue });
return visits.map(e => e.toJSON());
});