From ac7a113024ac2abe6c73f0f6dd3da571315fd6d3 Mon Sep 17 00:00:00 2001 From: Aaron Teo Date: Fri, 26 Jan 2024 22:29:23 +0800 Subject: [PATCH 1/6] refactor(functions): client checks handover to functions --- .../https/onCall/file/getClassification.ts | 58 +++++++++++++-- .../https/onCall/rekognition/getAuthToken.ts | 45 +++++++----- .../https/onCall/rekognition/getSessionId.ts | 73 ++++++++++++++++++- packages/shared/constants/collections.ts | 3 +- packages/shared/index.ts | 3 +- packages/shared/models/CFCallableBase.ts | 2 + .../models/CFCallableGetClassification.ts | 3 + .../shared/models/CFCallableGetSessionId.ts | 6 +- packages/shared/models/FSAudit.ts | 11 ++- packages/shared/models/FSDomain.ts | 10 +++ packages/shared/models/FSFile.ts | 1 + 11 files changed, 178 insertions(+), 37 deletions(-) create mode 100644 packages/shared/models/FSDomain.ts diff --git a/packages/functions/src/https/onCall/file/getClassification.ts b/packages/functions/src/https/onCall/file/getClassification.ts index e2bd5c2..6bf8d33 100644 --- a/packages/functions/src/https/onCall/file/getClassification.ts +++ b/packages/functions/src/https/onCall/file/getClassification.ts @@ -1,11 +1,17 @@ import type { FSAudit, + FSDomain, FSFile, CFCallableGetClassificationRequest, CFCallableGetClassificationResponse, } from '@armadillo/shared'; -import { FS_COLLECTION_AUDIT, FS_COLLECTION_FILES } from '@armadillo/shared'; +import { BlockList } from 'net'; +import { + FS_COLLECTION_AUDITS, + FS_COLLECTION_DOMAINS, + FS_COLLECTION_FILES, +} from '@armadillo/shared'; import { logger } from 'firebase-functions/v2'; import { HttpsError, onCall } from 'firebase-functions/v2/https'; @@ -27,7 +33,7 @@ export const https_onCall_file_getClassification = onCall => { logger.log(rawRequest); - const { origin, clientId, fileId } = data; + const { origin, clientId, clientOS, clientIPv4Address, clientDnsSuffix, fileId } = data; // Check if user is already authenticated if (auth) throw new HttpsError('failed-precondition', 'Authentication Error'); @@ -39,17 +45,33 @@ export const https_onCall_file_getClassification = onCall doc.data() as FSUser); - if (users.length < 1) continue; + const { ExternalImageId: externalImageId } = faceMatch.Face; + if (!externalImageId) continue; - const user = users[0]; - const authToken = await adminAuth.createCustomToken(user.uid); + try { + const fsUserSnapshot = await fsUserCol.doc(externalImageId).get(); + const fsUserData = fsUserSnapshot.data() as FSUser; + const authToken = await adminAuth.createCustomToken(fsUserData.uid); - return { token: authToken }; + return { token: authToken }; + } catch (error) { + logger.error(error); + throw new HttpsError('internal', 'Internal Error'); + } } - throw new HttpsError('unauthenticated', 'Unable to authenticate user'); + throw new HttpsError('unauthenticated', 'Unable to authenticate face'); } ); diff --git a/packages/functions/src/https/onCall/rekognition/getSessionId.ts b/packages/functions/src/https/onCall/rekognition/getSessionId.ts index b6d1f3b..1412b80 100644 --- a/packages/functions/src/https/onCall/rekognition/getSessionId.ts +++ b/packages/functions/src/https/onCall/rekognition/getSessionId.ts @@ -1,12 +1,17 @@ import type { + FSAudit, CFCallableGetSessionIdRequest, CFCallableGetSessionIdResponse, } from '@armadillo/shared'; +import { FS_COLLECTION_AUDITS, FS_COLLECTION_FILES } from '@armadillo/shared'; +import { RekognitionClient, CreateFaceLivenessSessionCommand } from '@aws-sdk/client-rekognition'; + import { logger } from 'firebase-functions/v2'; import { onCall, HttpsError } from 'firebase-functions/v2/https'; -import { RekognitionClient, CreateFaceLivenessSessionCommand } from '@aws-sdk/client-rekognition'; +import { firestore } from '../../../firebase'; +import { FieldValue } from 'firebase-admin/firestore'; /** * Retrieves a session ID from AWS Rekognition for the wrapper. @@ -22,7 +27,17 @@ export const https_onCall_rekognition_getSessionId = onCall => { logger.log(rawRequest); - const { origin, clientId } = data; + const { + origin, + clientId, + fileId, + fullScanEndTime, + antivirusSignaturesLastUpdated, + antispywareSignaturesLastUpdated, + } = data; + + const DAY_IN_MILLISECONDS = 86400000; // 24 hours + const MONTH_IN_MILLISECONDS = 2592000000; // 30 days const REKOGNITION_ACCESS_KEY_ID = process.env.REKOGNITION_ACCESS_KEY_ID; const REKOGNITION_ACCESS_KEY_SECRET = process.env.REKOGNITION_ACCESS_KEY_SECRET; @@ -49,7 +64,34 @@ export const https_onCall_rekognition_getSessionId = onCall= DAY_IN_MILLISECONDS) + throw new HttpsError('failed-precondition', 'Full Scan Outdated'); + + // Check if antivirus signatures last updated is outdated + if (antivirusSignaturesLastUpdated >= MONTH_IN_MILLISECONDS) + throw new HttpsError('failed-precondition', 'Antivirus Signatures Outdated'); + + // Check if antispyware signatures last updated is outdated + if (antispywareSignaturesLastUpdated >= MONTH_IN_MILLISECONDS) + throw new HttpsError('failed-precondition', 'Antispyware Signatures Outdated'); + + return { sessionId }; + } catch (error) { + logger.error(error); + throw new HttpsError('internal', 'Internal Error'); + } } ); diff --git a/packages/shared/constants/collections.ts b/packages/shared/constants/collections.ts index fe06c02..56679e6 100644 --- a/packages/shared/constants/collections.ts +++ b/packages/shared/constants/collections.ts @@ -1,3 +1,4 @@ export const FS_COLLECTION_USERS = 'users'; export const FS_COLLECTION_FILES = 'files'; -export const FS_COLLECTION_AUDIT = 'audits'; +export const FS_COLLECTION_AUDITS = 'audits'; +export const FS_COLLECTION_DOMAINS = 'domains'; diff --git a/packages/shared/index.ts b/packages/shared/index.ts index b8f9379..6f16c85 100644 --- a/packages/shared/index.ts +++ b/packages/shared/index.ts @@ -8,10 +8,11 @@ export * from './models/WrapperAppState'; export * from './models/WrapperIpc'; // Firestore Models +export * from './models/FSAudit'; export * from './models/FSUser'; +export * from './models/FSDomain'; export * from './models/FSFile'; export * from './models/FSFileClass'; -export * from './models/FSAudit'; export * from './models/FSMetadata'; // Cloud Functions Callable Models diff --git a/packages/shared/models/CFCallableBase.ts b/packages/shared/models/CFCallableBase.ts index b11d3a3..a376b6a 100644 --- a/packages/shared/models/CFCallableBase.ts +++ b/packages/shared/models/CFCallableBase.ts @@ -5,6 +5,8 @@ interface CFCallableBase { origin: 'web' | 'wrapper'; /** * Unique random client id generated by the wrapper application. + * Unique client id generated by the wrapper application. + * E.g., 'HOSTNAME::IPv4PRIVATE::RANDOMNUMBER' */ clientId: string; } diff --git a/packages/shared/models/CFCallableGetClassification.ts b/packages/shared/models/CFCallableGetClassification.ts index 2855159..9f5c77c 100644 --- a/packages/shared/models/CFCallableGetClassification.ts +++ b/packages/shared/models/CFCallableGetClassification.ts @@ -2,6 +2,9 @@ import type { FSFileClass, CFCallableBase } from '@armadillo/shared'; interface CFCallableGetClassificationRequest extends CFCallableBase { fileId: string; + clientOS: 'win32' | 'darwin' | 'linux'; + clientIPv4Address: string; + clientDnsSuffix: string; } interface CFCallableGetClassificationResponse { diff --git a/packages/shared/models/CFCallableGetSessionId.ts b/packages/shared/models/CFCallableGetSessionId.ts index 792b426..e2b78ce 100644 --- a/packages/shared/models/CFCallableGetSessionId.ts +++ b/packages/shared/models/CFCallableGetSessionId.ts @@ -1,8 +1,10 @@ import type { CFCallableBase } from '@armadillo/shared'; interface CFCallableGetSessionIdRequest extends CFCallableBase { - origin: 'web' | 'wrapper'; - clientId: string; + fileId: string; + fullScanEndTime: number; + antivirusSignaturesLastUpdated: number; + antispywareSignaturesLastUpdated: number; } interface CFCallableGetSessionIdResponse { diff --git a/packages/shared/models/FSAudit.ts b/packages/shared/models/FSAudit.ts index 387bb1f..ebdaa69 100644 --- a/packages/shared/models/FSAudit.ts +++ b/packages/shared/models/FSAudit.ts @@ -19,12 +19,15 @@ interface FSAuditFileClassification extends FSAuditBase { /** * Represents file classification step of the audit. */ - audit_step: 'FCLAS'; + audit_step: 'FILE_CLASSIFICATION'; /** * Represents the audit information for the file classification step. */ audit_info: { file_id: string; + client_os: string; + client_ipv4_address: string; + client_dns_suffix: string; }; } @@ -32,7 +35,7 @@ interface FSAuditDeviceCompromisation extends FSAuditBase { /** * Represents device compromisation step of the audit. */ - audit_step: 'DCOMP'; + audit_step: 'FACE_SESSION'; /** * Represents the audit information for the device compromisation step. */ @@ -47,7 +50,7 @@ interface FSAuditFaceAuthentication extends FSAuditBase { /** * Represents face authentication step of the audit. */ - audit_step: 'FAUTH'; + audit_step: 'FACE_AUTHENTICATION'; /** * Represents the audit information for the face authentication step. */ @@ -58,7 +61,7 @@ interface FSAuditFilePassword extends FSAuditBase { /** * Represents file password step of the audit. */ - audit_step: 'FPASS'; + audit_step: 'FILE_PASSWORD'; /** * Represents the audit information for the file password step. */ diff --git a/packages/shared/models/FSDomain.ts b/packages/shared/models/FSDomain.ts new file mode 100644 index 0000000..f902d15 --- /dev/null +++ b/packages/shared/models/FSDomain.ts @@ -0,0 +1,10 @@ +import type { FSMetadata } from '@armadillo/shared'; + +interface FSDomain extends FSMetadata { + domain_dns_suffix: string | null; + domain_ipv4_start: string | null; + domain_ipv4_end: string | null; + domain_administrators: string[]; +} + +export type { FSDomain }; diff --git a/packages/shared/models/FSFile.ts b/packages/shared/models/FSFile.ts index e8d12a2..a231024 100644 --- a/packages/shared/models/FSFile.ts +++ b/packages/shared/models/FSFile.ts @@ -2,6 +2,7 @@ import type { FSMetadata, FSFileClass } from '@armadillo/shared'; interface FSFile extends FSMetadata { readonly file_id: string; + readonly file_domain: string; readonly file_classification: FSFileClass; readonly file_name: string; readonly file_ext: string; From d3b393dcc287a822bf25da171a7f71ea3e123baf Mon Sep 17 00:00:00 2001 From: Aaron Teo Date: Mon, 5 Feb 2024 20:25:41 +0800 Subject: [PATCH 2/6] feat(backend,wrapper): add storage bucket ref --- apps/backend/src/lib/firebase/index.ts | 2 +- apps/backend/src/lib/firebase/storage.ts | 8 ++++++++ apps/wrapper/src/main/firebase/index.ts | 2 +- apps/wrapper/src/main/firebase/storage.ts | 8 ++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 apps/backend/src/lib/firebase/storage.ts create mode 100644 apps/wrapper/src/main/firebase/storage.ts diff --git a/apps/backend/src/lib/firebase/index.ts b/apps/backend/src/lib/firebase/index.ts index c9c59c1..ec6e2b2 100644 --- a/apps/backend/src/lib/firebase/index.ts +++ b/apps/backend/src/lib/firebase/index.ts @@ -15,7 +15,7 @@ const firebaseConfig = { appId: '1:515917548885:web:6d518785d21891c81a33dc', }; -const app = getApps().length ? getApp() : initializeApp(firebaseConfig); +export const app = getApps().length ? getApp() : initializeApp(firebaseConfig); export const auth = getAuth(app); export const storage = getStorage(app); diff --git a/apps/backend/src/lib/firebase/storage.ts b/apps/backend/src/lib/firebase/storage.ts new file mode 100644 index 0000000..86dea95 --- /dev/null +++ b/apps/backend/src/lib/firebase/storage.ts @@ -0,0 +1,8 @@ +import { getStorage } from 'firebase/storage'; + +import { app } from '$lib/firebase'; +import { BUCKET_TEMP, BUCKET_FILES, BUCKET_HEADSHOTS } from '@armadillo/shared'; + +export const tempStorage = getStorage(app, `gs://${BUCKET_TEMP}`); +export const fileStorage = getStorage(app, `gs://${BUCKET_FILES}`); +export const headshotStorage = getStorage(app, `gs://${BUCKET_HEADSHOTS}`); diff --git a/apps/wrapper/src/main/firebase/index.ts b/apps/wrapper/src/main/firebase/index.ts index 23a3920..91551ee 100644 --- a/apps/wrapper/src/main/firebase/index.ts +++ b/apps/wrapper/src/main/firebase/index.ts @@ -16,7 +16,7 @@ const firebaseConfig = { appId: '1:515917548885:web:40ffc233d9f2a3d31a33dc', }; -const app = getApps().length ? getApp() : initializeApp(firebaseConfig); +export const app = getApps().length ? getApp() : initializeApp(firebaseConfig); export const auth = getAuth(app); export const storage = getStorage(app); diff --git a/apps/wrapper/src/main/firebase/storage.ts b/apps/wrapper/src/main/firebase/storage.ts new file mode 100644 index 0000000..e123b7f --- /dev/null +++ b/apps/wrapper/src/main/firebase/storage.ts @@ -0,0 +1,8 @@ +import { getStorage } from 'firebase/storage'; + +import { app } from '../../main/firebase'; +import { BUCKET_TEMP, BUCKET_FILES, BUCKET_HEADSHOTS } from '@armadillo/shared'; + +export const tempStorage = getStorage(app, `gs://${BUCKET_TEMP}`); +export const fileStorage = getStorage(app, `gs://${BUCKET_FILES}`); +export const headshotStorage = getStorage(app, `gs://${BUCKET_HEADSHOTS}`); From 0138c4ee2fc9baae843d8d7b27cb6a1af1594a4c Mon Sep 17 00:00:00 2001 From: WhataTravesty Date: Tue, 6 Feb 2024 16:33:35 +0800 Subject: [PATCH 3/6] feat(backend): add file password component --- .../src/routes/fileupload/+page.svelte | 38 +- yarn.lock | 12430 ++++++++++++++++ 2 files changed, 12462 insertions(+), 6 deletions(-) create mode 100644 yarn.lock diff --git a/apps/backend/src/routes/fileupload/+page.svelte b/apps/backend/src/routes/fileupload/+page.svelte index d893289..e6ddb90 100644 --- a/apps/backend/src/routes/fileupload/+page.svelte +++ b/apps/backend/src/routes/fileupload/+page.svelte @@ -1,5 +1,5 @@ - - FileUpload - +{#if show} +