From 4129985369a64f47efa492fa9bc2fee11510c58f Mon Sep 17 00:00:00 2001 From: Christopher Langton Date: Mon, 30 Sep 2024 00:23:26 +1000 Subject: [PATCH] feat: refactor orgName to org relationship --- .../[installation_id]/install/[code].js | 30 ++++++++- functions/github/pat.js | 5 +- functions/github/repos/[org]/[repo]/sarif.js | 8 +-- functions/github/repos/[org]/[repo]/spdx.js | 4 +- functions/login/github/[code].js | 30 ++++++++- functions/me.js | 67 +++++++++++++------ functions/register/[org]/[email]/[hash].js | 45 ++++++++++--- functions/sarif/upload.js | 4 +- functions/vulncheck/integrate.js | 5 +- migrations/0011_org.sql | 59 ++++++++++++++++ package-lock.json | 64 +++++++++++++----- package.json | 2 +- prisma/schema.prisma | 14 +++- src/layouts/components/UserProfile.vue | 4 +- src/pages/GitHub.vue | 4 +- src/pages/Login.vue | 4 +- src/stores/notifications.js | 4 +- src/utils.js | 13 ---- wrangler.toml | 4 +- 19 files changed, 286 insertions(+), 84 deletions(-) create mode 100644 migrations/0011_org.sql diff --git a/functions/github/[installation_id]/install/[code].js b/functions/github/[installation_id]/install/[code].js index bbe43c2..a1f3aa3 100644 --- a/functions/github/[installation_id]/install/[code].js +++ b/functions/github/[installation_id]/install/[code].js @@ -76,15 +76,43 @@ export async function onRequestGet(context) { } else { let firstName = '' let lastName = '' + let orgId = crypto.randomUUID() if (!!content?.name) { const words = content.name.split(' ') firstName = words.shift() || '' lastName = words.join(' ') || '' } + if (content?.company) { + const originalOrg = await prisma.orgs.findFirst({ + where: { + name: content.company + } + }) + if (originalOrg?.uuid) { + orgId = originalOrg.uuid + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: content.company, + } + }) + console.log(`/github/install register orgId=${orgId}`, orgInfo) + } + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: memberEmail.toLowerCase(), + } + }) + console.log(`/github/install register orgId=${orgId}`, orgInfo) + } + response.member = { email: memberEmail.toLowerCase(), avatarUrl: content?.avatar_url || '', - orgName: content?.company || '', + orgId, passwordHash: await pbkdf2(oauthData.access_token), firstName, lastName diff --git a/functions/github/pat.js b/functions/github/pat.js index 854b301..33476a9 100644 --- a/functions/github/pat.js +++ b/functions/github/pat.js @@ -1,4 +1,4 @@ -import { GitHub, Server } from "@/utils"; +import { GitHub, Server, ensureStrReqBody } from "@/utils"; import { PrismaD1 } from '@prisma/adapter-d1'; import { PrismaClient } from '@prisma/client'; @@ -23,7 +23,8 @@ export async function onRequestPost(context) { if (!verificationResult.isValid) { return Response.json({ ok: false, result: verificationResult.message }) } - const body = await request.json() + const bodyStr = await ensureStrReqBody(request) + const body = JSON.parse(bodyStr) if (!body.token.startsWith('github_pat_')) { return Response.json({ error: { message: `Invalid PAT provided, expected "github_pat_" prefix.` } }) } diff --git a/functions/github/repos/[org]/[repo]/sarif.js b/functions/github/repos/[org]/[repo]/sarif.js index af541e0..bfa85b8 100644 --- a/functions/github/repos/[org]/[repo]/sarif.js +++ b/functions/github/repos/[org]/[repo]/sarif.js @@ -59,9 +59,9 @@ export async function onRequestGet(context) { } for (const data of content) { const objectPrefix = `github/${app.installationId}/repos/${repoName}/code-scanning/` - const reportInfo = await env.r2icache.put(`${objectPrefix}${data.report.id}.json`, JSON.stringify(data.report), putOptions) + const reportInfo = await env.r2artefact.put(`${objectPrefix}${data.report.id}.json`, JSON.stringify(data.report), putOptions) console.log(`${repoName}/code-scanning/${data.report.id}.json`, reportInfo) - const sarifInfo = await env.r2icache.put(`${objectPrefix}${data.report.id}_${data.report.sarif_id}.json`, JSON.stringify(data.sarif), putOptions) + const sarifInfo = await env.r2artefact.put(`${objectPrefix}${data.report.id}_${data.report.sarif_id}.json`, JSON.stringify(data.sarif), putOptions) console.log(`${repoName}/code-scanning/${data.report.id}_${data.report.sarif_id}.json`, sarifInfo) files.push(await process(prisma, verificationResult.session, data, repoName)) } @@ -82,9 +82,9 @@ export async function onRequestGet(context) { } for (const data of content) { const objectPrefix = `github/pat_${memberKey.id}/repos/${repoName}/code-scanning/` - const reportInfo = await env.r2icache.put(`${objectPrefix}${data.report.id}.json`, JSON.stringify(data.report), putOptions) + const reportInfo = await env.r2artefact.put(`${objectPrefix}${data.report.id}.json`, JSON.stringify(data.report), putOptions) console.log(`${repoName}/code-scanning/${data.report.id}.json`, reportInfo) - const sarifInfo = await env.r2icache.put(`${objectPrefix}${data.report.id}_${data.report.sarif_id}.json`, JSON.stringify(data.sarif), putOptions) + const sarifInfo = await env.r2artefact.put(`${objectPrefix}${data.report.id}_${data.report.sarif_id}.json`, JSON.stringify(data.sarif), putOptions) console.log(`${repoName}/code-scanning/${data.report.id}_${data.report.sarif_id}.json`, sarifInfo) files.push(await process(prisma, verificationResult.session, data, repoName)) } diff --git a/functions/github/repos/[org]/[repo]/spdx.js b/functions/github/repos/[org]/[repo]/spdx.js index 580470b..bc28d3b 100644 --- a/functions/github/repos/[org]/[repo]/spdx.js +++ b/functions/github/repos/[org]/[repo]/spdx.js @@ -68,7 +68,7 @@ export async function onRequestGet(context) { const { spdxId, spdxStr, findingIds } = await process(prisma, verificationResult.session, repoName, content) findings = [...findings, ...findingIds] const objectPrefix = `github/${app.installationId}/repos/${repoName}/sbom/` - console.log(`${repoName}/sbom/${spdxId}.json`, await env.r2icache.put(`${objectPrefix}${spdxId}.json`, spdxStr, putOptions)) + console.log(`${repoName}/sbom/${spdxId}.json`, await env.r2artefact.put(`${objectPrefix}${spdxId}.json`, spdxStr, putOptions)) files.push(content) } const memberKeys = await prisma.member_keys.findMany({ @@ -94,7 +94,7 @@ export async function onRequestGet(context) { const { spdxId, spdxStr, findingIds } = await process(prisma, verificationResult.session, repoName, content) findings = [...findings, ...findingIds] const objectPrefix = `github/pat_${memberKey.id}/repos/${repoName}/sbom/` - console.log(`${repoName}/sbom/${spdxId}.json`, await env.r2icache.put(`${objectPrefix}${spdxId}.json`, spdxStr, putOptions)) + console.log(`${repoName}/sbom/${spdxId}.json`, await env.r2artefact.put(`${objectPrefix}${spdxId}.json`, spdxStr, putOptions)) files.push({ spdx: content, errors }) } diff --git a/functions/login/github/[code].js b/functions/login/github/[code].js index a15ff8d..10f6e23 100644 --- a/functions/login/github/[code].js +++ b/functions/login/github/[code].js @@ -76,15 +76,43 @@ export async function onRequestGet(context) { } else { let firstName = '' let lastName = '' + let orgId = crypto.randomUUID() if (!!content?.name) { const words = content.name.split(' ') firstName = words.shift() || '' lastName = words.join(' ') || '' } + if (content?.company) { + const originalOrg = await prisma.orgs.findFirst({ + where: { + name: content.company + } + }) + if (originalOrg?.uuid) { + orgId = originalOrg.uuid + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: content.company, + } + }) + console.log(`/github/install register orgId=${orgId}`, orgInfo) + } + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: memberEmail.toLowerCase(), + } + }) + console.log(`/github/install register orgId=${orgId}`, orgInfo) + } + response.member = { email: memberEmail.toLowerCase(), avatarUrl: content?.avatar_url || '', - orgName: content?.company || '', + orgId, passwordHash: await pbkdf2(oauthData.access_token), firstName, lastName diff --git a/functions/me.js b/functions/me.js index 4230b40..0652724 100644 --- a/functions/me.js +++ b/functions/me.js @@ -1,4 +1,4 @@ -import { AuthResult, Server } from "@/utils"; +import { AuthResult, Server, ensureStrReqBody } from "@/utils"; import { PrismaD1 } from '@prisma/adapter-d1'; import { PrismaClient } from '@prisma/client'; @@ -28,6 +28,16 @@ export async function onRequestGet(context) { where: { email: verificationResult.session.memberEmail, }, + omit: { + orgId: true + }, + include: { + org: { + omit: { + members: true + } + } + }, }) delete member.passwordHash return Response.json({ ok: true, member }) @@ -58,54 +68,73 @@ export async function onRequestPost(context) { if (!verificationResult.isValid) { return Response.json({ ok: false, result: verificationResult.message }) } - const original = await prisma.members.findFirst({ + const originalMember = await prisma.members.findFirst({ where: { email: verificationResult.session.memberEmail, }, }) const member = {} - const data = await request.json() - if (data?.email && original.email !== data.email) { + const body = await ensureStrReqBody(request) + const data = JSON.parse(body) + if (data?.email && originalMember.email !== data.email) { member.email = data.email.toLowerCase() } - if (data?.passwordHash && original.passwordHash !== data.passwordHash) { + if (data?.passwordHash && originalMember.passwordHash !== data.passwordHash) { member.passwordHash = data.passwordHash } - if (data?.firstName && original.firstName !== data.firstName) { + if (data?.firstName && originalMember.firstName !== data.firstName) { member.firstName = data.firstName } - if (data?.lastName && original.lastName !== data.lastName) { + if (data?.lastName && originalMember.lastName !== data.lastName) { member.lastName = data.lastName } - if (data?.avatarUrl && original.avatarUrl !== data.avatarUrl) { + if (data?.avatarUrl && originalMember.avatarUrl !== data.avatarUrl) { member.avatarUrl = data.avatarUrl } - if (data?.orgName && original.orgName !== data.orgName) { - member.orgName = data.orgName - } - if (typeof data?.alertNews !== 'undefined' && original.alertNews !== data.alertNews) { + if (typeof data?.alertNews !== 'undefined' && originalMember.alertNews !== data.alertNews) { member.alertNews = parseInt(data.alertNews, 10) } - if (typeof data?.alertOverdue !== 'undefined' && original.alertOverdue !== data.alertOverdue) { + if (typeof data?.alertOverdue !== 'undefined' && originalMember.alertOverdue !== data.alertOverdue) { member.alertOverdue = parseInt(data.alertOverdue, 10) } - if (typeof data?.alertFindings !== 'undefined' && original.alertFindings !== data.alertFindings) { + if (typeof data?.alertFindings !== 'undefined' && originalMember.alertFindings !== data.alertFindings) { member.alertFindings = parseInt(data.alertFindings, 10) } - if (typeof data?.alertType !== 'undefined' && original.alertType !== data.alertType) { + if (typeof data?.alertType !== 'undefined' && originalMember.alertType !== data.alertType) { member.alertType = parseInt(data.alertType, 10) } + let updatedOrg = false + const originalOrg = await prisma.orgs.findFirst({ + where: { + uuid: originalMember.orgId, + }, + }) + if (data?.orgName && originalOrg.name !== data.orgName) { + //TODO: temp until organisations feature is finished + const orgInfo = await prisma.orgs.update({ + where: { + uuid: originalMember.orgId, + }, + data: { + name: data.orgName + } + }) + updatedOrg = true + console.log(`/me update org ${originalMember.orgId} ${data.orgName}`, orgInfo) + } + if (Object.keys(member).length > 0) { - await prisma.members.update({ + const memberInfo = await prisma.members.update({ where: { - email: verificationResult.session.memberEmail.toLowerCase(), + uuid: originalMember.uuid, }, data: member }) + console.log(`/me update member ${verificationResult.session.memberEmail}`, memberInfo) - return Response.json({ ok: true }) + return Response.json({ ok: true, result: 'Updated' }) } - return Response.json({ ok: false, result: 'No Change' }) + return Response.json({ ok: updatedOrg, result: updatedOrg ? 'Updated organisation' : 'No Change' }) } catch (err) { console.error(err) diff --git a/functions/register/[org]/[email]/[hash].js b/functions/register/[org]/[email]/[hash].js index 0ce2977..56684de 100644 --- a/functions/register/[org]/[email]/[hash].js +++ b/functions/register/[org]/[email]/[hash].js @@ -24,18 +24,45 @@ export async function onRequestGet(context) { params?.email && params?.hash ) { - console.log('org', params.org) - - const info = await prisma.members.create({ - data: { - orgName: params.org, - email: params.email.toLowerCase(), - passwordHash: await pbkdf2(params.hash) + let orgId = crypto.randomUUID() + if (params?.org) { + const originalOrg = await prisma.orgs.findFirst({ + where: { + name: params.org + } + }) + if (originalOrg?.uuid) { + orgId = originalOrg.uuid + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: params.org, + } + }) + console.log(`/register orgId=${orgId}`, orgInfo) } + } else { + const orgInfo = await prisma.orgs.create({ + data: { + uuid: orgId, + name: params.email.toLowerCase(), + } + }) + console.log(`/register orgId=${orgId}`, orgInfo) + } + const member = { + uuid: crypto.randomUUID(), + email: params.email.toLowerCase(), + orgId, + passwordHash: await pbkdf2(params.hash) + } + const info = await prisma.members.create({ + data: member }) - console.log(`/register email=${params.email}`, info) + console.log(`/register email=${member.email}`, info) - return Response.json(info) + return Response.json({ ok: true, member }) } return Response.json({ error: { message: 'missing properties /register/[org]/[email]/[sha1]' } }) diff --git a/functions/sarif/upload.js b/functions/sarif/upload.js index 4337ae5..93bbc3a 100644 --- a/functions/sarif/upload.js +++ b/functions/sarif/upload.js @@ -1,4 +1,4 @@ -import { Server, UUID, hex, isSARIF, ensureStrReqBody } from "@/utils"; +import { Server, hex, isSARIF, ensureStrReqBody } from "@/utils"; import { PrismaD1 } from '@prisma/adapter-d1'; import { PrismaClient } from '@prisma/client'; @@ -32,7 +32,7 @@ export async function onRequestPost(context) { if (!isSARIF(sarif)) { return Response.json({ ok: false, error: { message: 'SARIF is missing necessary fields.' } }) } - const sarifId = UUID() + const sarifId = crypto.randomUUID() const createdAt = (new Date()).getTime() for (const run of sarif.runs) { const reportId = await hex(run.tool.driver.name + run.tool.driver.semanticVersion + JSON.stringify(run.results)) diff --git a/functions/vulncheck/integrate.js b/functions/vulncheck/integrate.js index fc50e93..14d7910 100644 --- a/functions/vulncheck/integrate.js +++ b/functions/vulncheck/integrate.js @@ -1,4 +1,4 @@ -import { AuthResult, Server } from "@/utils"; +import { AuthResult, Server, ensureStrReqBody } from "@/utils"; import { PrismaD1 } from '@prisma/adapter-d1'; import { PrismaClient } from '@prisma/client'; @@ -24,7 +24,8 @@ export async function onRequestPost(context) { if (!verificationResult.isValid) { return Response.json({ ok: false, result: verificationResult.message }) } - const data = await request.json() + const bodyStr = await ensureStrReqBody(request) + const data = JSON.parse(bodyStr) if (!data.apiKey.startsWith('vulncheck_')) { return Response.json({ error: { message: `Invalid API Key provided, expected "vulncheck_" prefix.` } }) } diff --git a/migrations/0011_org.sql b/migrations/0011_org.sql new file mode 100644 index 0000000..340226a --- /dev/null +++ b/migrations/0011_org.sql @@ -0,0 +1,59 @@ +CREATE TABLE IF NOT EXISTS "orgs" ( + "uuid" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL +); +INSERT INTO "orgs" ("uuid", "name") +SELECT upper( + hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' || substr(hex(randomblob(2)), 2) || '-' || substr('AB89', 1 + (abs(random()) % 4), 1) || substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6)) + ), + "orgname" +FROM "members"; +CREATE TABLE "new_members" ( + "uuid" TEXT NOT NULL PRIMARY KEY, + "email" TEXT NOT NULL, + "orgId" TEXT, + "passwordHash" TEXT NOT NULL, + "avatarUrl" TEXT, + "firstName" TEXT, + "lastName" TEXT, + "alertNews" INTEGER NOT NULL DEFAULT 0, + "alertOverdue" INTEGER NOT NULL DEFAULT 0, + "alertFindings" INTEGER NOT NULL DEFAULT 0, + "alertType" INTEGER NOT NULL DEFAULT 0 +); +INSERT INTO "new_members" ( + "uuid", + "alertFindings", + "alertNews", + "alertOverdue", + "alertType", + "avatarUrl", + "orgId", + "email", + "firstName", + "lastName", + "passwordHash" + ) +SELECT upper( + hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' || substr(hex(randomblob(2)), 2) || '-' || substr('AB89', 1 + (abs(random()) % 4), 1) || substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6)) + ), + "alertFindings", + "alertNews", + "alertOverdue", + "alertType", + "avatarUrl", + ( + SELECT "uuid" + FROM "orgs" + WHERE "name" = orgName + LIMIT 1 + ) as "orgId", + "email", + "firstName", + "lastName", + "passwordHash" +FROM "members"; +DROP TABLE "members"; +ALTER TABLE "new_members" + RENAME TO "members"; +CREATE UNIQUE INDEX "members_email_key" ON "members"("email"); diff --git a/package-lock.json b/package-lock.json index df2ab3f..f5242ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,7 @@ "eslint-plugin-unicorn": "^47.0.0", "eslint-plugin-vue": "^9.13.0", "postcss-html": "^1.5.0", - "prisma": "^5.18.0", + "prisma": "^5.20.0", "stylelint": "14.15.0", "stylelint-config-idiomatic-order": "^10.0.0", "stylelint-config-standard-scss": "6.1.0", @@ -1479,40 +1479,69 @@ } }, "node_modules/@prisma/engines": { - "version": "5.18.0", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.20.0.tgz", + "integrity": "sha512-DtqkP+hcZvPEbj8t8dK5df2b7d3B8GNauKqaddRRqQBBlgkbdhJkxhoJTrOowlS3vaRt2iMCkU0+CSNn0KhqAQ==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0", - "@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", - "@prisma/fetch-engine": "5.18.0", - "@prisma/get-platform": "5.18.0" + "@prisma/debug": "5.20.0", + "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "@prisma/fetch-engine": "5.20.0", + "@prisma/get-platform": "5.20.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", + "version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284.tgz", + "integrity": "sha512-Lg8AS5lpi0auZe2Mn4gjuCg081UZf88k3cn0RCwHgR+6cyHHpttPZBElJTHf83ZGsRNAmVCZCfUGA57WB4u4JA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines/node_modules/@prisma/debug": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.20.0.tgz", + "integrity": "sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.18.0", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.20.0.tgz", + "integrity": "sha512-JVcaPXC940wOGpCOwuqQRTz6I9SaBK0c1BAyC1pcz9xBi+dzFgUu3G/p9GV1FhFs9OKpfSpIhQfUJE9y00zhqw==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0", - "@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", - "@prisma/get-platform": "5.18.0" + "@prisma/debug": "5.20.0", + "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "@prisma/get-platform": "5.20.0" } }, + "node_modules/@prisma/fetch-engine/node_modules/@prisma/debug": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.20.0.tgz", + "integrity": "sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==", + "devOptional": true, + "license": "Apache-2.0" + }, "node_modules/@prisma/get-platform": { - "version": "5.18.0", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.20.0.tgz", + "integrity": "sha512-8/+CehTZZNzJlvuryRgc77hZCWrUDYd/PmlZ7p2yNXtmf2Una4BWnTbak3us6WVdqoz5wmptk6IhsXdG2v5fmA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0" + "@prisma/debug": "5.20.0" } }, + "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.20.0.tgz", + "integrity": "sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==", + "devOptional": true, + "license": "Apache-2.0" + }, "node_modules/@rollup/pluginutils": { "version": "5.1.0", "license": "MIT", @@ -7151,18 +7180,23 @@ "license": "Unlicense" }, "node_modules/prisma": { - "version": "5.18.0", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.20.0.tgz", + "integrity": "sha512-6obb3ucKgAnsGS9x9gLOe8qa51XxvJ3vLQtmyf52CTey1Qcez3A6W6ROH5HIz5Q5bW+0VpmZb8WBohieMFGpig==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.18.0" + "@prisma/engines": "5.20.0" }, "bin": { "prisma": "build/index.js" }, "engines": { "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" } }, "node_modules/prismjs": { diff --git a/package.json b/package.json index 8cce980..cde1de2 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-unicorn": "^47.0.0", "eslint-plugin-vue": "^9.13.0", "postcss-html": "^1.5.0", - "prisma": "^5.18.0", + "prisma": "^5.20.0", "stylelint": "14.15.0", "stylelint-config-idiomatic-order": "^10.0.0", "stylelint-config-standard-scss": "6.1.0", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c79ea59..3e20668 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -21,9 +21,17 @@ model sessions { authn_ua String? } +model orgs { + uuid String @id @default(uuid()) + name String + members members[] +} + model members { - email String @id @unique - orgName String? + uuid String @id @default(uuid()) + email String @unique + orgId String? + org orgs? @relation(fields: [orgId], references: [uuid]) passwordHash String avatarUrl String? firstName String? @@ -34,7 +42,7 @@ model members { alertType Int @default(0) sarif sarif[] github_apps github_apps[] - git_repos git_repos[] + repos git_repos[] member_keys member_keys[] sessions sessions[] spdx spdx[] diff --git a/src/layouts/components/UserProfile.vue b/src/layouts/components/UserProfile.vue index e256802..56f8724 100644 --- a/src/layouts/components/UserProfile.vue +++ b/src/layouts/components/UserProfile.vue @@ -25,8 +25,8 @@ class Controller { if (data?.member?.avatarUrl) { Member.avatarUrl = data.member.avatarUrl } - if (data?.member?.orgName) { - Member.orgName = data.member.orgName + if (data?.member?.org?.name) { + Member.orgName = data.member.org.name } if (data?.member?.firstName) { Member.firstName = data.member.firstName diff --git a/src/pages/GitHub.vue b/src/pages/GitHub.vue index 140453b..682f99f 100644 --- a/src/pages/GitHub.vue +++ b/src/pages/GitHub.vue @@ -466,8 +466,8 @@ function persistData(data) { if (data?.member?.avatarUrl) { Member.avatarUrl = data.member.avatarUrl } - if (data?.member?.orgName) { - Member.orgName = data.member.orgName + if (data?.member?.org?.name) { + Member.orgName = data.member.org.name } if (data?.member?.firstName) { Member.firstName = data.member.firstName diff --git a/src/pages/Login.vue b/src/pages/Login.vue index 0bdad5a..041d987 100644 --- a/src/pages/Login.vue +++ b/src/pages/Login.vue @@ -49,8 +49,8 @@ class Controller { if (data?.member?.avatarUrl) { Member.avatarUrl = data.member.avatarUrl } - if (data?.member?.orgName) { - Member.orgName = data.member.orgName + if (data?.member?.org?.name) { + Member.orgName = data.member.org.name } if (data?.member?.firstName) { Member.firstName = data.member.firstName diff --git a/src/stores/notifications.js b/src/stores/notifications.js index 7779422..28624cb 100644 --- a/src/stores/notifications.js +++ b/src/stores/notifications.js @@ -1,4 +1,4 @@ -import { isJSON, UUID } from '@/utils'; +import { isJSON } from '@/utils'; import { defineStore } from 'pinia'; const storedQueue = localStorage.getItem('/app/notifications') || '' @@ -12,7 +12,7 @@ export const useNotificationsStore = defineStore('notifications', { }), actions: { add(item, key = 'notificationId') { - const notificationId = item?.[key] || UUID() + const notificationId = item?.[key] || crypto.randomUUID() const exists = this.state.filter(i => i[key] === notificationId).length > 0 if (!exists) { item.notificationId = notificationId diff --git a/src/utils.js b/src/utils.js index 18533b2..b4f6544 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1437,19 +1437,6 @@ export async function hex(text, name = "SHA-1") { return [...new Uint8Array(await crypto.subtle.digest({ name }, new TextEncoder().encode(text)))].map(b => b.toString(16).padStart(2, '0')).join('') } -/** - * Generates a version 4 UUID (Universally Unique Identifier). - * - * This function uses a combination of a fixed template and random numbers to create a unique identifier. - * - * @returns {string} A UUID in the format "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx". - */ -export function UUID() { - return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c => - (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16) - ) -} - export const round = (n, p = 100) => Math.round((n + Number.EPSILON) * p) / p export const isJSON = str => { diff --git a/wrangler.toml b/wrangler.toml index 9113a73..6178b98 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -15,8 +15,8 @@ database_name = "vulnetix" database_id = "15dc7c29-05a9-46c2-b87b-89b1a4f32d33" [[r2_buckets]] -binding = 'r2icache' -bucket_name = 'integrations-cache' +binding = 'r2artefact' +bucket_name = 'artefact' [[r2_buckets]] binding = 'r2webhooks'