CREDENTIAL TYPE MANAGEMENT WORKS
This commit is contained in:
+981
@@ -0,0 +1,981 @@
|
||||
# TTSCM API Routes Documentation
|
||||
|
||||
This document provides a comprehensive overview of all API routes available in the TTSCM API.
|
||||
|
||||
## Base URL
|
||||
|
||||
```
|
||||
http://localhost:3000/v1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication Routes
|
||||
|
||||
### Get Authentication URI
|
||||
|
||||
**GET** `/auth/uri`
|
||||
|
||||
Get the Microsoft OAuth authentication URI for user login.
|
||||
|
||||
**Authentication Required:** No
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Successfully fetch Auth URI",
|
||||
"data": {
|
||||
"uri": "https://login.microsoftonline.com/...",
|
||||
"callbackKey": "ck123..."
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### OAuth Redirect Handler
|
||||
|
||||
**GET** `/auth/redirect`
|
||||
|
||||
Handles the OAuth redirect callback from Microsoft. This endpoint processes the authorization code and creates a user session.
|
||||
|
||||
**Authentication Required:** No
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `code` - Authorization code from Microsoft
|
||||
- `state` - Callback key for WebSocket notification
|
||||
|
||||
**Response:**
|
||||
Closes the browser window and emits authentication tokens via WebSocket.
|
||||
|
||||
---
|
||||
|
||||
### Refresh Access Token
|
||||
|
||||
**POST** `/auth/refresh`
|
||||
|
||||
Refresh an expired access token using a valid refresh token.
|
||||
|
||||
**Authentication Required:** Yes (Refresh Token)
|
||||
|
||||
**Headers:**
|
||||
|
||||
- `x-refresh-token` - The refresh token
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 201,
|
||||
"message": "Token refreshed successfully!",
|
||||
"data": {
|
||||
"accessToken": "eyJhbGc...",
|
||||
"refreshToken": "eyJhbGc..."
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Routes
|
||||
|
||||
### Get Current User
|
||||
|
||||
**GET** `/user/@me`
|
||||
|
||||
Fetch the currently authenticated user's information.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Scopes:** `user.read`
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Fetched user.",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com",
|
||||
"login": "john.doe",
|
||||
"image": "https://...",
|
||||
"roles": ["admin"],
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-02-14T00:00:00.000Z"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Current User
|
||||
|
||||
**PATCH** `/user/@me`
|
||||
|
||||
Update the currently authenticated user's information.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Scopes:** `user.write`
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Jane Doe",
|
||||
"image": "https://example.com/avatar.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Successfully updated user.",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "Jane Doe",
|
||||
"email": "jane.doe@example.com",
|
||||
"image": "https://example.com/avatar.jpg"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Company Routes
|
||||
|
||||
### Get All Companies
|
||||
|
||||
**GET** `/company/companies`
|
||||
|
||||
Fetch a paginated list of all companies with optional search functionality.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `company.fetch.many`
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `page` (optional) - Page number (default: 1)
|
||||
- `rpp` (optional) - Records per page (default: 30)
|
||||
- `search` (optional) - Search query to filter companies
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Companies Fetched Successfully!",
|
||||
"data": [
|
||||
{
|
||||
"id": "ckx...",
|
||||
"name": "Acme Corp",
|
||||
"cw_CompanyId": 12345,
|
||||
"cw_Identifier": "AcmeCorp"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"previousPage": null,
|
||||
"currentPage": 1,
|
||||
"nextPage": 2,
|
||||
"totalPages": 10,
|
||||
"totalRecords": 300,
|
||||
"listedRecords": 30
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Company by ID
|
||||
|
||||
**GET** `/company/companies/:identifier`
|
||||
|
||||
Fetch a single company by its ID.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `company.fetch`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `identifier` - Company ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Company Fetched Successfully!",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "Acme Corp",
|
||||
"cw_CompanyId": 12345,
|
||||
"cw_Identifier": "AcmeCorp"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Company Configurations
|
||||
|
||||
**GET** `/company/companies/:identifier/configurations`
|
||||
|
||||
Fetch configurations for a specific company from ConnectWise.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `company.fetch`, `company.fetch.configurations`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `identifier` - Company ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Company Configurations Fetched Successfully!",
|
||||
"data": {
|
||||
// ConnectWise configuration data
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Credential Routes
|
||||
|
||||
### Get Credential by ID
|
||||
|
||||
**GET** `/credential/credentials/:id`
|
||||
|
||||
Fetch a single credential by its ID.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.fetch`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Fetched Successfully!",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "AWS Credentials",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": {
|
||||
"accountId": "123456789"
|
||||
},
|
||||
"type": {
|
||||
"id": "cky...",
|
||||
"name": "AWS",
|
||||
"fields": [...],
|
||||
"permissionScope": "aws.credentials"
|
||||
},
|
||||
"company": {
|
||||
"id": "ckz...",
|
||||
"name": "Acme Corp"
|
||||
},
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-02-14T00:00:00.000Z"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Credentials by Company
|
||||
|
||||
**GET** `/credential/credentials/company/:companyId`
|
||||
|
||||
Fetch all credentials associated with a specific company.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.fetch.many`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `companyId` - Company ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Company Credentials Fetched Successfully!",
|
||||
"data": [
|
||||
{
|
||||
"id": "ckx...",
|
||||
"name": "AWS Credentials",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": {...},
|
||||
"type": {...},
|
||||
"company": {...}
|
||||
}
|
||||
],
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Create Credential
|
||||
|
||||
**POST** `/credential/credentials`
|
||||
|
||||
Create a new credential with validated and encrypted fields.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.create`
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Production AWS Credentials",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": [
|
||||
{
|
||||
"id": "ckx1...",
|
||||
"fieldId": "accessKeyId",
|
||||
"value": "AKIAIOSFODNN7EXAMPLE"
|
||||
},
|
||||
{
|
||||
"id": "ckx2...",
|
||||
"fieldId": "secretAccessKey",
|
||||
"value": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 201,
|
||||
"message": "Credential Created Successfully!",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "Production AWS Credentials",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": {...}
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Credential
|
||||
|
||||
**PATCH** `/credential/credentials/:id`
|
||||
|
||||
Update a credential's basic properties (name).
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.update`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Updated Credential Name"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Updated Successfully!",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "Updated Credential Name",
|
||||
...
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Credential Fields
|
||||
|
||||
**PUT** `/credential/credentials/:id/fields`
|
||||
|
||||
Validate and update credential field values. Secure fields are automatically encrypted.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.update`, `credential.fields.update`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"id": "ckx1...",
|
||||
"fieldId": "accessKeyId",
|
||||
"value": "AKIAIOSFODNN7NEWVALUE"
|
||||
},
|
||||
{
|
||||
"id": "ckx2...",
|
||||
"fieldId": "secretAccessKey",
|
||||
"value": "newSecretKeyValue123"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Fields Updated Successfully!",
|
||||
"data": {
|
||||
"id": "ckx...",
|
||||
"name": "Production AWS Credentials",
|
||||
"fields": {...}
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Credential Fields
|
||||
|
||||
**GET** `/credential/credentials/:id/fields`
|
||||
|
||||
Fetch all field values for a credential (secure fields returned encrypted).
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.fetch`, `credential.fields.fetch`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Fields Fetched Successfully!",
|
||||
"data": [
|
||||
{
|
||||
"id": "ckx-accessKeyId",
|
||||
"fieldId": "accessKeyId",
|
||||
"value": "AKIAIOSFODNN7EXAMPLE"
|
||||
},
|
||||
{
|
||||
"id": "ckx1...",
|
||||
"fieldId": "secretAccessKey",
|
||||
"value": "base64EncryptedValue=="
|
||||
}
|
||||
],
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Read Secure Values
|
||||
|
||||
**GET** `/credential/credentials/:id/secure-values`
|
||||
|
||||
Decrypt and return all secure field values for a credential.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.fetch`, `credential.secure_values.read`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Secure Values Fetched Successfully!",
|
||||
"data": {
|
||||
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"apiKey": "sk_live_123456789abcdef"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Delete Credential
|
||||
|
||||
**DELETE** `/credential/credentials/:id`
|
||||
|
||||
Delete a credential and all associated secure values.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential.delete`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Deleted Successfully!",
|
||||
"data": null,
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Credential Type Routes
|
||||
|
||||
### Get Credential Type by ID or Name
|
||||
|
||||
**GET** `/credential-type/credential-types/:identifier`
|
||||
|
||||
Fetch a single credential type by its ID or name.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.fetch`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `identifier` - Credential Type ID or name
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Type Fetched Successfully!",
|
||||
"data": {
|
||||
"id": "cky...",
|
||||
"name": "AWS",
|
||||
"permissionScope": "aws.credentials",
|
||||
"icon": "https://aws.amazon.com/favicon.ico",
|
||||
"fields": [
|
||||
{
|
||||
"id": "accessKeyId",
|
||||
"name": "Access Key ID",
|
||||
"required": true,
|
||||
"secure": false,
|
||||
"valueType": "plain_text"
|
||||
},
|
||||
{
|
||||
"id": "secretAccessKey",
|
||||
"name": "Secret Access Key",
|
||||
"required": true,
|
||||
"secure": true,
|
||||
"valueType": "password"
|
||||
}
|
||||
],
|
||||
"credentialCount": 5,
|
||||
"createdAt": "2026-01-01T00:00:00.000Z",
|
||||
"updatedAt": "2026-02-14T00:00:00.000Z"
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get All Credential Types
|
||||
|
||||
**GET** `/credential-type/credential-types`
|
||||
|
||||
Fetch all credential types in the system.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.fetch.many`
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Types Fetched Successfully!",
|
||||
"data": [
|
||||
{
|
||||
"id": "cky...",
|
||||
"name": "AWS",
|
||||
"permissionScope": "aws.credentials",
|
||||
"icon": "https://aws.amazon.com/favicon.ico",
|
||||
"fields": [...],
|
||||
"credentialCount": 5
|
||||
},
|
||||
{
|
||||
"id": "ckz...",
|
||||
"name": "Azure",
|
||||
"permissionScope": "azure.credentials",
|
||||
"icon": "https://azure.microsoft.com/favicon.ico",
|
||||
"fields": [...],
|
||||
"credentialCount": 3
|
||||
}
|
||||
],
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Create Credential Type
|
||||
|
||||
**POST** `/credential-type/credential-types`
|
||||
|
||||
Create a new credential type with field definitions.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.create`
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "GitHub",
|
||||
"permissionScope": "github.credentials",
|
||||
"icon": "https://github.com/favicon.ico",
|
||||
"fields": [
|
||||
{
|
||||
"id": "username",
|
||||
"name": "Username",
|
||||
"required": true,
|
||||
"secure": false,
|
||||
"valueType": "plain_text"
|
||||
},
|
||||
{
|
||||
"id": "personalAccessToken",
|
||||
"name": "Personal Access Token",
|
||||
"required": true,
|
||||
"secure": true,
|
||||
"valueType": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 201,
|
||||
"message": "Credential Type Created Successfully!",
|
||||
"data": {
|
||||
"id": "ck1...",
|
||||
"name": "GitHub",
|
||||
"permissionScope": "github.credentials",
|
||||
"icon": "https://github.com/favicon.ico",
|
||||
"fields": [...]
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Update Credential Type
|
||||
|
||||
**PATCH** `/credential-type/credential-types/:id`
|
||||
|
||||
Update a credential type's properties or field definitions.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.update`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential Type ID
|
||||
|
||||
**Request Body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "GitHub Enterprise",
|
||||
"icon": "https://github.enterprise.com/favicon.ico",
|
||||
"fields": [
|
||||
{
|
||||
"id": "username",
|
||||
"name": "Username",
|
||||
"required": true,
|
||||
"secure": false,
|
||||
"valueType": "plain_text"
|
||||
},
|
||||
{
|
||||
"id": "personalAccessToken",
|
||||
"name": "Personal Access Token",
|
||||
"required": true,
|
||||
"secure": true,
|
||||
"valueType": "password"
|
||||
},
|
||||
{
|
||||
"id": "enterpriseUrl",
|
||||
"name": "Enterprise URL",
|
||||
"required": true,
|
||||
"secure": false,
|
||||
"valueType": "plain_text"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Type Updated Successfully!",
|
||||
"data": {
|
||||
"id": "ck1...",
|
||||
"name": "GitHub Enterprise",
|
||||
"fields": [...]
|
||||
},
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Delete Credential Type
|
||||
|
||||
**DELETE** `/credential-type/credential-types/:id`
|
||||
|
||||
Delete a credential type. This will cascade delete all credentials of this type.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.delete`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential Type ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credential Type Deleted Successfully!",
|
||||
"data": null,
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Get Credentials by Type
|
||||
|
||||
**GET** `/credential-type/credential-types/:id/credentials`
|
||||
|
||||
Fetch all credentials that use a specific credential type.
|
||||
|
||||
**Authentication Required:** Yes
|
||||
|
||||
**Required Permissions:** `credential_type.fetch`, `credential.fetch.many`
|
||||
|
||||
**URL Parameters:**
|
||||
|
||||
- `id` - Credential Type ID
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 200,
|
||||
"message": "Credentials Fetched Successfully!",
|
||||
"data": [
|
||||
{
|
||||
"id": "ckx...",
|
||||
"name": "Production AWS",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": {...}
|
||||
},
|
||||
{
|
||||
"id": "ck2...",
|
||||
"name": "Staging AWS",
|
||||
"typeId": "cky...",
|
||||
"companyId": "ckz...",
|
||||
"fields": {...}
|
||||
}
|
||||
],
|
||||
"successful": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Utility Routes
|
||||
|
||||
### Teapot
|
||||
|
||||
**GET** `/teapot`
|
||||
|
||||
A fun Easter egg endpoint that returns HTTP 418 (I'm a teapot).
|
||||
|
||||
**Authentication Required:** No
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 418,
|
||||
"message": "I'm a teapot",
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
All endpoints may return error responses in the following format:
|
||||
|
||||
### 400 Bad Request
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 400,
|
||||
"message": "Validation error",
|
||||
"errors": [
|
||||
{
|
||||
"path": ["field"],
|
||||
"message": "Field is required"
|
||||
}
|
||||
],
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
### 401 Unauthorized
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 401,
|
||||
"message": "Unauthorized",
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
### 403 Forbidden
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 403,
|
||||
"message": "Insufficient permissions",
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
### 404 Not Found
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 404,
|
||||
"message": "Resource not found",
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
### 500 Internal Server Error
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 500,
|
||||
"message": "Internal server error",
|
||||
"successful": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
Most endpoints require authentication via an access token in the request headers:
|
||||
|
||||
```
|
||||
Authorization: Bearer <access_token>
|
||||
```
|
||||
|
||||
Tokens are obtained through the Microsoft OAuth flow:
|
||||
|
||||
1. Call `GET /auth/uri` to get the authentication URL
|
||||
2. Redirect user to the Microsoft login page
|
||||
3. User authenticates and is redirected to `/auth/redirect`
|
||||
4. Access and refresh tokens are provided via WebSocket or response
|
||||
5. Use the access token in subsequent API requests
|
||||
|
||||
When the access token expires, use `POST /auth/refresh` with the refresh token to obtain a new access token.
|
||||
|
||||
---
|
||||
|
||||
## Permission System
|
||||
|
||||
The API uses a granular permission system. Each endpoint requires specific permissions that are checked via the `authMiddleware`. Permissions are granted through roles assigned to users.
|
||||
|
||||
Common permission patterns:
|
||||
|
||||
- `resource.fetch` - Read a single resource
|
||||
- `resource.fetch.many` - Read multiple resources
|
||||
- `resource.create` - Create a new resource
|
||||
- `resource.update` - Update a resource
|
||||
- `resource.delete` - Delete a resource
|
||||
- `resource.field.action` - Perform specific field operations
|
||||
|
||||
Users can have multiple roles, and permissions are accumulated from all assigned roles.
|
||||
@@ -12,6 +12,7 @@
|
||||
"@prisma/client": "^7.3.0",
|
||||
"@socket.io/bun-engine": "^0.1.0",
|
||||
"axios": "^1.13.3",
|
||||
"blakets": "^0.1.12",
|
||||
"cors": "^2.8.6",
|
||||
"cuid": "^3.0.0",
|
||||
"hono": "^4.11.5",
|
||||
@@ -84,6 +85,8 @@
|
||||
|
||||
"@prisma/studio-core": ["@prisma/studio-core@0.13.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg=="],
|
||||
|
||||
"@prokopschield/argv": ["@prokopschield/argv@0.1.3", "", { "bin": { "argv": "lib/cli.js" } }, "sha512-4/yMUKdaFIKBUOOu5+qhC2kMuAECk7FaKamo5NSu4iAzuw36hj6E3UY3CYVKXPnA5dldwiwW60Ss5Ss5QdxVCw=="],
|
||||
|
||||
"@socket.io/bun-engine": ["@socket.io/bun-engine@0.1.0", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-B1z6GuAxZlfvjgaa3BHZBOfqHJNfnpebTw15p+Un1HuBL4YM7wUxO9sJa7K4NDTe7XbUBeqLIwTDA5tOOjffog=="],
|
||||
|
||||
"@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="],
|
||||
@@ -112,6 +115,8 @@
|
||||
|
||||
"base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="],
|
||||
|
||||
"blakets": ["blakets@0.1.12", "", { "dependencies": { "@prokopschield/argv": "^0.1.0-2" }, "bin": { "blake": "lib/demo.js", "blake2b": "lib/cli.js", "blake2s": "lib/cli.js", "blakejs": "lib/demo.js", "blakets": "lib/demo.js" } }, "sha512-ReOnLTDRlbExlTXbJZoA2xkvhzauJ7ldpvhKnb1cUNw8gdAHWHWOWG8XMjwpxQmmEZCDAR7VZiM5BYTUSOLVrw=="],
|
||||
|
||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
||||
|
||||
@@ -37,3 +37,18 @@ export type Role = Prisma.RoleModel
|
||||
*
|
||||
*/
|
||||
export type Company = Prisma.CompanyModel
|
||||
/**
|
||||
* Model CredentialType
|
||||
*
|
||||
*/
|
||||
export type CredentialType = Prisma.CredentialTypeModel
|
||||
/**
|
||||
* Model SecureValue
|
||||
*
|
||||
*/
|
||||
export type SecureValue = Prisma.SecureValueModel
|
||||
/**
|
||||
* Model Credential
|
||||
*
|
||||
*/
|
||||
export type Credential = Prisma.CredentialModel
|
||||
|
||||
@@ -59,3 +59,18 @@ export type Role = Prisma.RoleModel
|
||||
*
|
||||
*/
|
||||
export type Company = Prisma.CompanyModel
|
||||
/**
|
||||
* Model CredentialType
|
||||
*
|
||||
*/
|
||||
export type CredentialType = Prisma.CredentialTypeModel
|
||||
/**
|
||||
* Model SecureValue
|
||||
*
|
||||
*/
|
||||
export type SecureValue = Prisma.SecureValueModel
|
||||
/**
|
||||
* Model Credential
|
||||
*
|
||||
*/
|
||||
export type Credential = Prisma.CredentialModel
|
||||
|
||||
@@ -175,6 +175,57 @@ export type IntWithAggregatesFilter<$PrismaModel = never> = {
|
||||
_max?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type JsonFilter<$PrismaModel = never> =
|
||||
| Prisma.PatchUndefined<
|
||||
Prisma.Either<Required<JsonFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonFilterBase<$PrismaModel>>, 'path'>>,
|
||||
Required<JsonFilterBase<$PrismaModel>>
|
||||
>
|
||||
| Prisma.OptionalFlat<Omit<Required<JsonFilterBase<$PrismaModel>>, 'path'>>
|
||||
|
||||
export type JsonFilterBase<$PrismaModel = never> = {
|
||||
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
path?: string[]
|
||||
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
}
|
||||
|
||||
export type JsonWithAggregatesFilter<$PrismaModel = never> =
|
||||
| Prisma.PatchUndefined<
|
||||
Prisma.Either<Required<JsonWithAggregatesFilterBase<$PrismaModel>>, Exclude<keyof Required<JsonWithAggregatesFilterBase<$PrismaModel>>, 'path'>>,
|
||||
Required<JsonWithAggregatesFilterBase<$PrismaModel>>
|
||||
>
|
||||
| Prisma.OptionalFlat<Omit<Required<JsonWithAggregatesFilterBase<$PrismaModel>>, 'path'>>
|
||||
|
||||
export type JsonWithAggregatesFilterBase<$PrismaModel = never> = {
|
||||
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
path?: string[]
|
||||
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedJsonFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedJsonFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedStringFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
@@ -349,4 +400,28 @@ export type NestedFloatFilter<$PrismaModel = never> = {
|
||||
not?: Prisma.NestedFloatFilter<$PrismaModel> | number
|
||||
}
|
||||
|
||||
export type NestedJsonFilter<$PrismaModel = never> =
|
||||
| Prisma.PatchUndefined<
|
||||
Prisma.Either<Required<NestedJsonFilterBase<$PrismaModel>>, Exclude<keyof Required<NestedJsonFilterBase<$PrismaModel>>, 'path'>>,
|
||||
Required<NestedJsonFilterBase<$PrismaModel>>
|
||||
>
|
||||
| Prisma.OptionalFlat<Omit<Required<NestedJsonFilterBase<$PrismaModel>>, 'path'>>
|
||||
|
||||
export type NestedJsonFilterBase<$PrismaModel = never> = {
|
||||
equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
path?: string[]
|
||||
mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel>
|
||||
string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null
|
||||
lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel>
|
||||
not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = {
|
||||
"clientVersion": "7.3.0",
|
||||
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
|
||||
"activeProvider": "postgresql",
|
||||
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId String @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Company {\n id String @id @default(cuid())\n name String\n\n cw_CompanyId Int @unique\n cw_Identifier String @unique\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n",
|
||||
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId String @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Company {\n id String @id @default(cuid())\n name String\n\n cw_CompanyId Int @unique\n cw_Identifier String @unique\n\n credentials Credential[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel CredentialType {\n id String @id @default(cuid())\n name String @unique\n\n permissionScope String\n icon String?\n fields Json\n\n credentials Credential[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel SecureValue {\n id String @id @default(cuid())\n name String\n\n content String // Encrypted content\n hash String // Hash of the original content for integrity verification and Search\n\n credentialId String\n credential Credential @relation(fields: [credentialId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Credential {\n id String @id @default(cuid())\n name String\n\n typeId String\n type CredentialType @relation(fields: [typeId], references: [id], onDelete: Cascade)\n\n fields Json\n\n companyId String\n company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)\n\n securevalues SecureValue[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n",
|
||||
"runtimeDataModel": {
|
||||
"models": {},
|
||||
"enums": {},
|
||||
@@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Company\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"cw_CompanyId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"cw_Identifier\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Company\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"cw_CompanyId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"cw_Identifier\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"credentials\",\"kind\":\"object\",\"type\":\"Credential\",\"relationName\":\"CompanyToCredential\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"CredentialType\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissionScope\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"icon\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"fields\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"credentials\",\"kind\":\"object\",\"type\":\"Credential\",\"relationName\":\"CredentialToCredentialType\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"SecureValue\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hash\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"credentialId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"credential\",\"kind\":\"object\",\"type\":\"Credential\",\"relationName\":\"CredentialToSecureValue\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Credential\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"typeId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"object\",\"type\":\"CredentialType\",\"relationName\":\"CredentialToCredentialType\"},{\"name\":\"fields\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"companyId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"company\",\"kind\":\"object\",\"type\":\"Company\",\"relationName\":\"CompanyToCredential\"},{\"name\":\"securevalues\",\"kind\":\"object\",\"type\":\"SecureValue\",\"relationName\":\"CredentialToSecureValue\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||
|
||||
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||
const { Buffer } = await import('node:buffer')
|
||||
@@ -215,6 +215,36 @@ export interface PrismaClient<
|
||||
* ```
|
||||
*/
|
||||
get company(): Prisma.CompanyDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
|
||||
/**
|
||||
* `prisma.credentialType`: Exposes CRUD operations for the **CredentialType** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more CredentialTypes
|
||||
* const credentialTypes = await prisma.credentialType.findMany()
|
||||
* ```
|
||||
*/
|
||||
get credentialType(): Prisma.CredentialTypeDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
|
||||
/**
|
||||
* `prisma.secureValue`: Exposes CRUD operations for the **SecureValue** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more SecureValues
|
||||
* const secureValues = await prisma.secureValue.findMany()
|
||||
* ```
|
||||
*/
|
||||
get secureValue(): Prisma.SecureValueDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
|
||||
/**
|
||||
* `prisma.credential`: Exposes CRUD operations for the **Credential** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Credentials
|
||||
* const credentials = await prisma.credential.findMany()
|
||||
* ```
|
||||
*/
|
||||
get credential(): Prisma.CredentialDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
}
|
||||
|
||||
export function getPrismaClientClass(): PrismaClientConstructor {
|
||||
|
||||
@@ -387,7 +387,10 @@ export const ModelName = {
|
||||
Session: 'Session',
|
||||
User: 'User',
|
||||
Role: 'Role',
|
||||
Company: 'Company'
|
||||
Company: 'Company',
|
||||
CredentialType: 'CredentialType',
|
||||
SecureValue: 'SecureValue',
|
||||
Credential: 'Credential'
|
||||
} as const
|
||||
|
||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||
@@ -403,7 +406,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
||||
omit: GlobalOmitOptions
|
||||
}
|
||||
meta: {
|
||||
modelProps: "session" | "user" | "role" | "company"
|
||||
modelProps: "session" | "user" | "role" | "company" | "credentialType" | "secureValue" | "credential"
|
||||
txIsolationLevel: TransactionIsolationLevel
|
||||
}
|
||||
model: {
|
||||
@@ -703,6 +706,228 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
|
||||
}
|
||||
}
|
||||
}
|
||||
CredentialType: {
|
||||
payload: Prisma.$CredentialTypePayload<ExtArgs>
|
||||
fields: Prisma.CredentialTypeFieldRefs
|
||||
operations: {
|
||||
findUnique: {
|
||||
args: Prisma.CredentialTypeFindUniqueArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload> | null
|
||||
}
|
||||
findUniqueOrThrow: {
|
||||
args: Prisma.CredentialTypeFindUniqueOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
findFirst: {
|
||||
args: Prisma.CredentialTypeFindFirstArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload> | null
|
||||
}
|
||||
findFirstOrThrow: {
|
||||
args: Prisma.CredentialTypeFindFirstOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
findMany: {
|
||||
args: Prisma.CredentialTypeFindManyArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>[]
|
||||
}
|
||||
create: {
|
||||
args: Prisma.CredentialTypeCreateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
createMany: {
|
||||
args: Prisma.CredentialTypeCreateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
createManyAndReturn: {
|
||||
args: Prisma.CredentialTypeCreateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>[]
|
||||
}
|
||||
delete: {
|
||||
args: Prisma.CredentialTypeDeleteArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
update: {
|
||||
args: Prisma.CredentialTypeUpdateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
deleteMany: {
|
||||
args: Prisma.CredentialTypeDeleteManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateMany: {
|
||||
args: Prisma.CredentialTypeUpdateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateManyAndReturn: {
|
||||
args: Prisma.CredentialTypeUpdateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>[]
|
||||
}
|
||||
upsert: {
|
||||
args: Prisma.CredentialTypeUpsertArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialTypePayload>
|
||||
}
|
||||
aggregate: {
|
||||
args: Prisma.CredentialTypeAggregateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.AggregateCredentialType>
|
||||
}
|
||||
groupBy: {
|
||||
args: Prisma.CredentialTypeGroupByArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.CredentialTypeGroupByOutputType>[]
|
||||
}
|
||||
count: {
|
||||
args: Prisma.CredentialTypeCountArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.CredentialTypeCountAggregateOutputType> | number
|
||||
}
|
||||
}
|
||||
}
|
||||
SecureValue: {
|
||||
payload: Prisma.$SecureValuePayload<ExtArgs>
|
||||
fields: Prisma.SecureValueFieldRefs
|
||||
operations: {
|
||||
findUnique: {
|
||||
args: Prisma.SecureValueFindUniqueArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload> | null
|
||||
}
|
||||
findUniqueOrThrow: {
|
||||
args: Prisma.SecureValueFindUniqueOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
findFirst: {
|
||||
args: Prisma.SecureValueFindFirstArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload> | null
|
||||
}
|
||||
findFirstOrThrow: {
|
||||
args: Prisma.SecureValueFindFirstOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
findMany: {
|
||||
args: Prisma.SecureValueFindManyArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>[]
|
||||
}
|
||||
create: {
|
||||
args: Prisma.SecureValueCreateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
createMany: {
|
||||
args: Prisma.SecureValueCreateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
createManyAndReturn: {
|
||||
args: Prisma.SecureValueCreateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>[]
|
||||
}
|
||||
delete: {
|
||||
args: Prisma.SecureValueDeleteArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
update: {
|
||||
args: Prisma.SecureValueUpdateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
deleteMany: {
|
||||
args: Prisma.SecureValueDeleteManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateMany: {
|
||||
args: Prisma.SecureValueUpdateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateManyAndReturn: {
|
||||
args: Prisma.SecureValueUpdateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>[]
|
||||
}
|
||||
upsert: {
|
||||
args: Prisma.SecureValueUpsertArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$SecureValuePayload>
|
||||
}
|
||||
aggregate: {
|
||||
args: Prisma.SecureValueAggregateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.AggregateSecureValue>
|
||||
}
|
||||
groupBy: {
|
||||
args: Prisma.SecureValueGroupByArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.SecureValueGroupByOutputType>[]
|
||||
}
|
||||
count: {
|
||||
args: Prisma.SecureValueCountArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.SecureValueCountAggregateOutputType> | number
|
||||
}
|
||||
}
|
||||
}
|
||||
Credential: {
|
||||
payload: Prisma.$CredentialPayload<ExtArgs>
|
||||
fields: Prisma.CredentialFieldRefs
|
||||
operations: {
|
||||
findUnique: {
|
||||
args: Prisma.CredentialFindUniqueArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload> | null
|
||||
}
|
||||
findUniqueOrThrow: {
|
||||
args: Prisma.CredentialFindUniqueOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
findFirst: {
|
||||
args: Prisma.CredentialFindFirstArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload> | null
|
||||
}
|
||||
findFirstOrThrow: {
|
||||
args: Prisma.CredentialFindFirstOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
findMany: {
|
||||
args: Prisma.CredentialFindManyArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>[]
|
||||
}
|
||||
create: {
|
||||
args: Prisma.CredentialCreateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
createMany: {
|
||||
args: Prisma.CredentialCreateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
createManyAndReturn: {
|
||||
args: Prisma.CredentialCreateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>[]
|
||||
}
|
||||
delete: {
|
||||
args: Prisma.CredentialDeleteArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
update: {
|
||||
args: Prisma.CredentialUpdateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
deleteMany: {
|
||||
args: Prisma.CredentialDeleteManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateMany: {
|
||||
args: Prisma.CredentialUpdateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateManyAndReturn: {
|
||||
args: Prisma.CredentialUpdateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>[]
|
||||
}
|
||||
upsert: {
|
||||
args: Prisma.CredentialUpsertArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$CredentialPayload>
|
||||
}
|
||||
aggregate: {
|
||||
args: Prisma.CredentialAggregateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.AggregateCredential>
|
||||
}
|
||||
groupBy: {
|
||||
args: Prisma.CredentialGroupByArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.CredentialGroupByOutputType>[]
|
||||
}
|
||||
count: {
|
||||
args: Prisma.CredentialCountArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.CredentialCountAggregateOutputType> | number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} & {
|
||||
other: {
|
||||
@@ -796,6 +1021,45 @@ export const CompanyScalarFieldEnum = {
|
||||
export type CompanyScalarFieldEnum = (typeof CompanyScalarFieldEnum)[keyof typeof CompanyScalarFieldEnum]
|
||||
|
||||
|
||||
export const CredentialTypeScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
permissionScope: 'permissionScope',
|
||||
icon: 'icon',
|
||||
fields: 'fields',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type CredentialTypeScalarFieldEnum = (typeof CredentialTypeScalarFieldEnum)[keyof typeof CredentialTypeScalarFieldEnum]
|
||||
|
||||
|
||||
export const SecureValueScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
content: 'content',
|
||||
hash: 'hash',
|
||||
credentialId: 'credentialId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type SecureValueScalarFieldEnum = (typeof SecureValueScalarFieldEnum)[keyof typeof SecureValueScalarFieldEnum]
|
||||
|
||||
|
||||
export const CredentialScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
typeId: 'typeId',
|
||||
fields: 'fields',
|
||||
companyId: 'companyId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type CredentialScalarFieldEnum = (typeof CredentialScalarFieldEnum)[keyof typeof CredentialScalarFieldEnum]
|
||||
|
||||
|
||||
export const SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
@@ -804,6 +1068,13 @@ export const SortOrder = {
|
||||
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||
|
||||
|
||||
export const JsonNullValueInput = {
|
||||
JsonNull: JsonNull
|
||||
} as const
|
||||
|
||||
export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput]
|
||||
|
||||
|
||||
export const QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
@@ -820,6 +1091,15 @@ export const NullsOrder = {
|
||||
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||
|
||||
|
||||
export const JsonNullValueFilter = {
|
||||
DbNull: DbNull,
|
||||
JsonNull: JsonNull,
|
||||
AnyNull: AnyNull
|
||||
} as const
|
||||
|
||||
export type JsonNullValueFilter = (typeof JsonNullValueFilter)[keyof typeof JsonNullValueFilter]
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Field references
|
||||
@@ -875,6 +1155,20 @@ export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel,
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Json'
|
||||
*/
|
||||
export type JsonFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Json'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'QueryMode'
|
||||
*/
|
||||
export type EnumQueryModeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'QueryMode'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Float'
|
||||
*/
|
||||
@@ -987,6 +1281,9 @@ export type GlobalOmitConfig = {
|
||||
user?: Prisma.UserOmit
|
||||
role?: Prisma.RoleOmit
|
||||
company?: Prisma.CompanyOmit
|
||||
credentialType?: Prisma.CredentialTypeOmit
|
||||
secureValue?: Prisma.SecureValueOmit
|
||||
credential?: Prisma.CredentialOmit
|
||||
}
|
||||
|
||||
/* Types for Logging */
|
||||
|
||||
@@ -54,7 +54,10 @@ export const ModelName = {
|
||||
Session: 'Session',
|
||||
User: 'User',
|
||||
Role: 'Role',
|
||||
Company: 'Company'
|
||||
Company: 'Company',
|
||||
CredentialType: 'CredentialType',
|
||||
SecureValue: 'SecureValue',
|
||||
Credential: 'Credential'
|
||||
} as const
|
||||
|
||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||
@@ -127,6 +130,45 @@ export const CompanyScalarFieldEnum = {
|
||||
export type CompanyScalarFieldEnum = (typeof CompanyScalarFieldEnum)[keyof typeof CompanyScalarFieldEnum]
|
||||
|
||||
|
||||
export const CredentialTypeScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
permissionScope: 'permissionScope',
|
||||
icon: 'icon',
|
||||
fields: 'fields',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type CredentialTypeScalarFieldEnum = (typeof CredentialTypeScalarFieldEnum)[keyof typeof CredentialTypeScalarFieldEnum]
|
||||
|
||||
|
||||
export const SecureValueScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
content: 'content',
|
||||
hash: 'hash',
|
||||
credentialId: 'credentialId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type SecureValueScalarFieldEnum = (typeof SecureValueScalarFieldEnum)[keyof typeof SecureValueScalarFieldEnum]
|
||||
|
||||
|
||||
export const CredentialScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
typeId: 'typeId',
|
||||
fields: 'fields',
|
||||
companyId: 'companyId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
} as const
|
||||
|
||||
export type CredentialScalarFieldEnum = (typeof CredentialScalarFieldEnum)[keyof typeof CredentialScalarFieldEnum]
|
||||
|
||||
|
||||
export const SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
@@ -135,6 +177,13 @@ export const SortOrder = {
|
||||
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||
|
||||
|
||||
export const JsonNullValueInput = {
|
||||
JsonNull: JsonNull
|
||||
} as const
|
||||
|
||||
export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput]
|
||||
|
||||
|
||||
export const QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
@@ -150,3 +199,12 @@ export const NullsOrder = {
|
||||
|
||||
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||
|
||||
|
||||
export const JsonNullValueFilter = {
|
||||
DbNull: DbNull,
|
||||
JsonNull: JsonNull,
|
||||
AnyNull: AnyNull
|
||||
} as const
|
||||
|
||||
export type JsonNullValueFilter = (typeof JsonNullValueFilter)[keyof typeof JsonNullValueFilter]
|
||||
|
||||
|
||||
@@ -12,4 +12,7 @@ export type * from './models/Session.ts'
|
||||
export type * from './models/User.ts'
|
||||
export type * from './models/Role.ts'
|
||||
export type * from './models/Company.ts'
|
||||
export type * from './models/CredentialType.ts'
|
||||
export type * from './models/SecureValue.ts'
|
||||
export type * from './models/Credential.ts'
|
||||
export type * from './commonInputTypes.ts'
|
||||
@@ -224,6 +224,7 @@ export type CompanyWhereInput = {
|
||||
cw_Identifier?: Prisma.StringFilter<"Company"> | string
|
||||
createdAt?: Prisma.DateTimeFilter<"Company"> | Date | string
|
||||
updatedAt?: Prisma.DateTimeFilter<"Company"> | Date | string
|
||||
credentials?: Prisma.CredentialListRelationFilter
|
||||
}
|
||||
|
||||
export type CompanyOrderByWithRelationInput = {
|
||||
@@ -233,6 +234,7 @@ export type CompanyOrderByWithRelationInput = {
|
||||
cw_Identifier?: Prisma.SortOrder
|
||||
createdAt?: Prisma.SortOrder
|
||||
updatedAt?: Prisma.SortOrder
|
||||
credentials?: Prisma.CredentialOrderByRelationAggregateInput
|
||||
}
|
||||
|
||||
export type CompanyWhereUniqueInput = Prisma.AtLeast<{
|
||||
@@ -245,6 +247,7 @@ export type CompanyWhereUniqueInput = Prisma.AtLeast<{
|
||||
name?: Prisma.StringFilter<"Company"> | string
|
||||
createdAt?: Prisma.DateTimeFilter<"Company"> | Date | string
|
||||
updatedAt?: Prisma.DateTimeFilter<"Company"> | Date | string
|
||||
credentials?: Prisma.CredentialListRelationFilter
|
||||
}, "id" | "cw_CompanyId" | "cw_Identifier">
|
||||
|
||||
export type CompanyOrderByWithAggregationInput = {
|
||||
@@ -280,6 +283,7 @@ export type CompanyCreateInput = {
|
||||
cw_Identifier: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
credentials?: Prisma.CredentialCreateNestedManyWithoutCompanyInput
|
||||
}
|
||||
|
||||
export type CompanyUncheckedCreateInput = {
|
||||
@@ -289,6 +293,7 @@ export type CompanyUncheckedCreateInput = {
|
||||
cw_Identifier: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
credentials?: Prisma.CredentialUncheckedCreateNestedManyWithoutCompanyInput
|
||||
}
|
||||
|
||||
export type CompanyUpdateInput = {
|
||||
@@ -298,6 +303,7 @@ export type CompanyUpdateInput = {
|
||||
cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
credentials?: Prisma.CredentialUpdateManyWithoutCompanyNestedInput
|
||||
}
|
||||
|
||||
export type CompanyUncheckedUpdateInput = {
|
||||
@@ -307,6 +313,7 @@ export type CompanyUncheckedUpdateInput = {
|
||||
cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
credentials?: Prisma.CredentialUncheckedUpdateManyWithoutCompanyNestedInput
|
||||
}
|
||||
|
||||
export type CompanyCreateManyInput = {
|
||||
@@ -371,6 +378,11 @@ export type CompanySumOrderByAggregateInput = {
|
||||
cw_CompanyId?: Prisma.SortOrder
|
||||
}
|
||||
|
||||
export type CompanyScalarRelationFilter = {
|
||||
is?: Prisma.CompanyWhereInput
|
||||
isNot?: Prisma.CompanyWhereInput
|
||||
}
|
||||
|
||||
export type IntFieldUpdateOperationsInput = {
|
||||
set?: number
|
||||
increment?: number
|
||||
@@ -379,6 +391,101 @@ export type IntFieldUpdateOperationsInput = {
|
||||
divide?: number
|
||||
}
|
||||
|
||||
export type CompanyCreateNestedOneWithoutCredentialsInput = {
|
||||
create?: Prisma.XOR<Prisma.CompanyCreateWithoutCredentialsInput, Prisma.CompanyUncheckedCreateWithoutCredentialsInput>
|
||||
connectOrCreate?: Prisma.CompanyCreateOrConnectWithoutCredentialsInput
|
||||
connect?: Prisma.CompanyWhereUniqueInput
|
||||
}
|
||||
|
||||
export type CompanyUpdateOneRequiredWithoutCredentialsNestedInput = {
|
||||
create?: Prisma.XOR<Prisma.CompanyCreateWithoutCredentialsInput, Prisma.CompanyUncheckedCreateWithoutCredentialsInput>
|
||||
connectOrCreate?: Prisma.CompanyCreateOrConnectWithoutCredentialsInput
|
||||
upsert?: Prisma.CompanyUpsertWithoutCredentialsInput
|
||||
connect?: Prisma.CompanyWhereUniqueInput
|
||||
update?: Prisma.XOR<Prisma.XOR<Prisma.CompanyUpdateToOneWithWhereWithoutCredentialsInput, Prisma.CompanyUpdateWithoutCredentialsInput>, Prisma.CompanyUncheckedUpdateWithoutCredentialsInput>
|
||||
}
|
||||
|
||||
export type CompanyCreateWithoutCredentialsInput = {
|
||||
id?: string
|
||||
name: string
|
||||
cw_CompanyId: number
|
||||
cw_Identifier: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
}
|
||||
|
||||
export type CompanyUncheckedCreateWithoutCredentialsInput = {
|
||||
id?: string
|
||||
name: string
|
||||
cw_CompanyId: number
|
||||
cw_Identifier: string
|
||||
createdAt?: Date | string
|
||||
updatedAt?: Date | string
|
||||
}
|
||||
|
||||
export type CompanyCreateOrConnectWithoutCredentialsInput = {
|
||||
where: Prisma.CompanyWhereUniqueInput
|
||||
create: Prisma.XOR<Prisma.CompanyCreateWithoutCredentialsInput, Prisma.CompanyUncheckedCreateWithoutCredentialsInput>
|
||||
}
|
||||
|
||||
export type CompanyUpsertWithoutCredentialsInput = {
|
||||
update: Prisma.XOR<Prisma.CompanyUpdateWithoutCredentialsInput, Prisma.CompanyUncheckedUpdateWithoutCredentialsInput>
|
||||
create: Prisma.XOR<Prisma.CompanyCreateWithoutCredentialsInput, Prisma.CompanyUncheckedCreateWithoutCredentialsInput>
|
||||
where?: Prisma.CompanyWhereInput
|
||||
}
|
||||
|
||||
export type CompanyUpdateToOneWithWhereWithoutCredentialsInput = {
|
||||
where?: Prisma.CompanyWhereInput
|
||||
data: Prisma.XOR<Prisma.CompanyUpdateWithoutCredentialsInput, Prisma.CompanyUncheckedUpdateWithoutCredentialsInput>
|
||||
}
|
||||
|
||||
export type CompanyUpdateWithoutCredentialsInput = {
|
||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number
|
||||
cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
}
|
||||
|
||||
export type CompanyUncheckedUpdateWithoutCredentialsInput = {
|
||||
id?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
name?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number
|
||||
cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string
|
||||
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Count Type CompanyCountOutputType
|
||||
*/
|
||||
|
||||
export type CompanyCountOutputType = {
|
||||
credentials: number
|
||||
}
|
||||
|
||||
export type CompanyCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
credentials?: boolean | CompanyCountOutputTypeCountCredentialsArgs
|
||||
}
|
||||
|
||||
/**
|
||||
* CompanyCountOutputType without action
|
||||
*/
|
||||
export type CompanyCountOutputTypeDefaultArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
/**
|
||||
* Select specific fields to fetch from the CompanyCountOutputType
|
||||
*/
|
||||
select?: Prisma.CompanyCountOutputTypeSelect<ExtArgs> | null
|
||||
}
|
||||
|
||||
/**
|
||||
* CompanyCountOutputType without action
|
||||
*/
|
||||
export type CompanyCountOutputTypeCountCredentialsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
where?: Prisma.CredentialWhereInput
|
||||
}
|
||||
|
||||
|
||||
export type CompanySelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||
@@ -388,6 +495,8 @@ export type CompanySelect<ExtArgs extends runtime.Types.Extensions.InternalArgs
|
||||
cw_Identifier?: boolean
|
||||
createdAt?: boolean
|
||||
updatedAt?: boolean
|
||||
credentials?: boolean | Prisma.Company$credentialsArgs<ExtArgs>
|
||||
_count?: boolean | Prisma.CompanyCountOutputTypeDefaultArgs<ExtArgs>
|
||||
}, ExtArgs["result"]["company"]>
|
||||
|
||||
export type CompanySelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
||||
@@ -418,10 +527,18 @@ export type CompanySelectScalar = {
|
||||
}
|
||||
|
||||
export type CompanyOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "cw_CompanyId" | "cw_Identifier" | "createdAt" | "updatedAt", ExtArgs["result"]["company"]>
|
||||
export type CompanyInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
credentials?: boolean | Prisma.Company$credentialsArgs<ExtArgs>
|
||||
_count?: boolean | Prisma.CompanyCountOutputTypeDefaultArgs<ExtArgs>
|
||||
}
|
||||
export type CompanyIncludeCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {}
|
||||
export type CompanyIncludeUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {}
|
||||
|
||||
export type $CompanyPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
name: "Company"
|
||||
objects: {}
|
||||
objects: {
|
||||
credentials: Prisma.$CredentialPayload<ExtArgs>[]
|
||||
}
|
||||
scalars: runtime.Types.Extensions.GetPayloadResult<{
|
||||
id: string
|
||||
name: string
|
||||
@@ -823,6 +940,7 @@ readonly fields: CompanyFieldRefs;
|
||||
*/
|
||||
export interface Prisma__CompanyClient<T, Null = never, ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> extends Prisma.PrismaPromise<T> {
|
||||
readonly [Symbol.toStringTag]: "PrismaPromise"
|
||||
credentials<T extends Prisma.Company$credentialsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Company$credentialsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$CredentialPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
@@ -874,6 +992,10 @@ export type CompanyFindUniqueArgs<ExtArgs extends runtime.Types.Extensions.Inter
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter, which Company to fetch.
|
||||
*/
|
||||
@@ -892,6 +1014,10 @@ export type CompanyFindUniqueOrThrowArgs<ExtArgs extends runtime.Types.Extension
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter, which Company to fetch.
|
||||
*/
|
||||
@@ -910,6 +1036,10 @@ export type CompanyFindFirstArgs<ExtArgs extends runtime.Types.Extensions.Intern
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter, which Company to fetch.
|
||||
*/
|
||||
@@ -958,6 +1088,10 @@ export type CompanyFindFirstOrThrowArgs<ExtArgs extends runtime.Types.Extensions
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter, which Company to fetch.
|
||||
*/
|
||||
@@ -1006,6 +1140,10 @@ export type CompanyFindManyArgs<ExtArgs extends runtime.Types.Extensions.Interna
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter, which Companies to fetch.
|
||||
*/
|
||||
@@ -1049,6 +1187,10 @@ export type CompanyCreateArgs<ExtArgs extends runtime.Types.Extensions.InternalA
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* The data needed to create a Company.
|
||||
*/
|
||||
@@ -1097,6 +1239,10 @@ export type CompanyUpdateArgs<ExtArgs extends runtime.Types.Extensions.InternalA
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* The data needed to update a Company.
|
||||
*/
|
||||
@@ -1163,6 +1309,10 @@ export type CompanyUpsertArgs<ExtArgs extends runtime.Types.Extensions.InternalA
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* The filter to search for the Company to update in case it exists.
|
||||
*/
|
||||
@@ -1189,6 +1339,10 @@ export type CompanyDeleteArgs<ExtArgs extends runtime.Types.Extensions.InternalA
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
/**
|
||||
* Filter which Company to delete.
|
||||
*/
|
||||
@@ -1209,6 +1363,30 @@ export type CompanyDeleteManyArgs<ExtArgs extends runtime.Types.Extensions.Inter
|
||||
limit?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Company.credentials
|
||||
*/
|
||||
export type Company$credentialsArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
||||
/**
|
||||
* Select specific fields to fetch from the Credential
|
||||
*/
|
||||
select?: Prisma.CredentialSelect<ExtArgs> | null
|
||||
/**
|
||||
* Omit specific fields from the Credential
|
||||
*/
|
||||
omit?: Prisma.CredentialOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CredentialInclude<ExtArgs> | null
|
||||
where?: Prisma.CredentialWhereInput
|
||||
orderBy?: Prisma.CredentialOrderByWithRelationInput | Prisma.CredentialOrderByWithRelationInput[]
|
||||
cursor?: Prisma.CredentialWhereUniqueInput
|
||||
take?: number
|
||||
skip?: number
|
||||
distinct?: Prisma.CredentialScalarFieldEnum | Prisma.CredentialScalarFieldEnum[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Company without action
|
||||
*/
|
||||
@@ -1221,4 +1399,8 @@ export type CompanyDefaultArgs<ExtArgs extends runtime.Types.Extensions.Internal
|
||||
* Omit specific fields from the Company
|
||||
*/
|
||||
omit?: Prisma.CompanyOmit<ExtArgs> | null
|
||||
/**
|
||||
* Choose, which related nodes to fetch as well
|
||||
*/
|
||||
include?: Prisma.CompanyInclude<ExtArgs> | null
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
||||
"@prisma/client": "^7.3.0",
|
||||
"@socket.io/bun-engine": "^0.1.0",
|
||||
"axios": "^1.13.3",
|
||||
"blakets": "^0.1.12",
|
||||
"cors": "^2.8.6",
|
||||
"cuid": "^3.0.0",
|
||||
"hono": "^4.11.5",
|
||||
|
||||
@@ -62,6 +62,54 @@ model Company {
|
||||
cw_CompanyId Int @unique
|
||||
cw_Identifier String @unique
|
||||
|
||||
credentials Credential[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model CredentialType {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
|
||||
permissionScope String
|
||||
icon String?
|
||||
fields Json
|
||||
|
||||
credentials Credential[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model SecureValue {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
|
||||
content String // Encrypted content
|
||||
hash String // Hash of the original content for integrity verification and Search
|
||||
|
||||
credentialId String
|
||||
credential Credential @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Credential {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
|
||||
typeId String
|
||||
type CredentialType @relation(fields: [typeId], references: [id], onDelete: Cascade)
|
||||
|
||||
fields Json
|
||||
|
||||
companyId String
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
|
||||
securevalues SecureValue[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
import { z } from "zod";
|
||||
|
||||
/* /v1/credential-type */
|
||||
export default createRoute(
|
||||
"post",
|
||||
["/"],
|
||||
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
permissionScope: z.string().min(1, "Permission scope is required"),
|
||||
icon: z.string().optional(),
|
||||
fields: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
required: z.boolean(),
|
||||
secure: z.boolean(),
|
||||
valueType: z.enum(["plain_text", "password"]),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
const data = schema.parse(body);
|
||||
|
||||
const credentialType = await credentialTypes.create(data as any);
|
||||
|
||||
const response = apiResponse.created(
|
||||
"Credential Type Created Successfully!",
|
||||
credentialType.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential_type.create"] }),
|
||||
);
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential-type/:id */
|
||||
export default createRoute(
|
||||
"delete",
|
||||
["/:id"],
|
||||
|
||||
async (c) => {
|
||||
await credentialTypes.delete(c.req.param("id"));
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Type Deleted Successfully!",
|
||||
null,
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential_type.delete"] }),
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential-type/:identifier */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/:identifier"],
|
||||
|
||||
async (c) => {
|
||||
const credentialType = await credentialTypes.fetch(
|
||||
c.req.param("identifier"),
|
||||
);
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Type Fetched Successfully!",
|
||||
credentialType.toJson({ includeCredentialCount: true }),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential_type.fetch"] }),
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential-type */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/"],
|
||||
|
||||
async (c) => {
|
||||
const allCredentialTypes = await credentialTypes.fetchAll();
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Types Fetched Successfully!",
|
||||
allCredentialTypes.map((ct) =>
|
||||
ct.toJson({ includeCredentialCount: true }),
|
||||
),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential_type.fetch.many"] }),
|
||||
);
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential-type/:id/credentials */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/:id/credentials"],
|
||||
|
||||
async (c) => {
|
||||
const credentialType = await credentialTypes.fetch(c.req.param("id"));
|
||||
const credentials = await credentialType.fetchCredentials();
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credentials Fetched Successfully!",
|
||||
credentials.map((cred) => cred.toJson()),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({
|
||||
permissions: ["credential_type.fetch", "credential.fetch.many"],
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
import { default as fetch } from "./fetch";
|
||||
import { default as fetchAll } from "./fetchAll";
|
||||
import { default as create } from "./create";
|
||||
import { default as update } from "./update";
|
||||
import { default as deleteCredentialType } from "./delete";
|
||||
import { default as fetchCredentials } from "./fetchCredentials";
|
||||
|
||||
export {
|
||||
fetch,
|
||||
fetchAll,
|
||||
create,
|
||||
update,
|
||||
deleteCredentialType as delete,
|
||||
fetchCredentials,
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentialTypes } from "../../managers/credentialTypes";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
import { z } from "zod";
|
||||
|
||||
/* /v1/credential-type/:id */
|
||||
export default createRoute(
|
||||
"patch",
|
||||
["/:id"],
|
||||
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
const credentialType = await credentialTypes.fetch(c.req.param("id"));
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().optional(),
|
||||
permissionScope: z.string().optional(),
|
||||
icon: z.string().optional(),
|
||||
fields: z
|
||||
.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
required: z.boolean(),
|
||||
secure: z.boolean(),
|
||||
valueType: z.enum(["plain_text", "password"]),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
});
|
||||
|
||||
const data = schema.parse(body);
|
||||
|
||||
await credentialType.update(data as any);
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Type Updated Successfully!",
|
||||
credentialType.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential_type.update"] }),
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
import { z } from "zod";
|
||||
|
||||
/* /v1/credential/create */
|
||||
export default createRoute(
|
||||
"post",
|
||||
["/credentials"],
|
||||
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1, "Name is required"),
|
||||
typeId: z.string().min(1, "Type ID is required"),
|
||||
companyId: z.string().min(1, "Company ID is required"),
|
||||
fields: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
fieldId: z.string(),
|
||||
value: z.string(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
const data = schema.parse(body);
|
||||
|
||||
const credential = await credentials.create(data);
|
||||
|
||||
const response = apiResponse.created(
|
||||
"Credential Created Successfully!",
|
||||
credential.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential.create"] }),
|
||||
);
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential/:id */
|
||||
export default createRoute(
|
||||
"delete",
|
||||
["/credentials/:id"],
|
||||
|
||||
async (c) => {
|
||||
await credentials.delete(c.req.param("id"));
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Deleted Successfully!",
|
||||
null,
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential.delete"] }),
|
||||
);
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential/:id */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/credentials/:id"],
|
||||
|
||||
async (c) => {
|
||||
const credential = await credentials.fetch(c.req.param("id"));
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Fetched Successfully!",
|
||||
credential.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential.fetch"] }),
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential/company/:companyId */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/credentials/company/:companyId"],
|
||||
|
||||
async (c) => {
|
||||
const companyCredentials = await credentials.fetchByCompany(
|
||||
c.req.param("companyId"),
|
||||
);
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Company Credentials Fetched Successfully!",
|
||||
companyCredentials.map((cred) => cred.toJson()),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential.fetch.many"] }),
|
||||
);
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential/:id/fields */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/credentials/:id/fields"],
|
||||
|
||||
async (c) => {
|
||||
const credential = await credentials.fetch(c.req.param("id"));
|
||||
const fields = await credential.fetchAllFieldValues();
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Fields Fetched Successfully!",
|
||||
fields,
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({
|
||||
permissions: ["credential.fetch", "credential.fields.fetch"],
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
import { default as fetch } from "./fetch";
|
||||
import { default as fetchByCompany } from "./fetchByCompany";
|
||||
import { default as create } from "./create";
|
||||
import { default as update } from "./update";
|
||||
import { default as updateFields } from "./updateFields";
|
||||
import { default as fetchFields } from "./fetchFields";
|
||||
import { default as readSecureValues } from "./readSecureValues";
|
||||
import { default as deleteCredential } from "./delete";
|
||||
|
||||
export {
|
||||
fetch,
|
||||
fetchByCompany,
|
||||
create,
|
||||
update,
|
||||
updateFields,
|
||||
fetchFields,
|
||||
readSecureValues,
|
||||
deleteCredential as delete,
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
|
||||
/* /v1/credential/:id/secure-values */
|
||||
export default createRoute(
|
||||
"get",
|
||||
["/credentials/:id/secure-values"],
|
||||
|
||||
async (c) => {
|
||||
const credential = await credentials.fetch(c.req.param("id"));
|
||||
const secureValues = await credential.readAllSecureValues();
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Secure Values Fetched Successfully!",
|
||||
secureValues,
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({
|
||||
permissions: ["credential.fetch", "credential.secure_values.read"],
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
import { z } from "zod";
|
||||
|
||||
/* /v1/credential/:id */
|
||||
export default createRoute(
|
||||
"patch",
|
||||
["/credentials/:id"],
|
||||
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
const credential = await credentials.fetch(c.req.param("id"));
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().optional(),
|
||||
});
|
||||
|
||||
const data = schema.parse(body);
|
||||
|
||||
await credential.update(data);
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Updated Successfully!",
|
||||
credential.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({ permissions: ["credential.update"] }),
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Hono } from "hono/tiny";
|
||||
import { createRoute } from "../../modules/api-utils/createRoute";
|
||||
import { credentials } from "../../managers/credentials";
|
||||
import { apiResponse } from "../../modules/api-utils/apiResponse";
|
||||
import { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import { authMiddleware } from "../middleware/authorization";
|
||||
import { z } from "zod";
|
||||
|
||||
/* /v1/credential/:id/fields */
|
||||
export default createRoute(
|
||||
"put",
|
||||
["/credentials/:id/fields"],
|
||||
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
const credential = await credentials.fetch(c.req.param("id"));
|
||||
|
||||
const schema = z.object({
|
||||
fields: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
fieldId: z.string(),
|
||||
value: z.string(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
const data = schema.parse(body);
|
||||
|
||||
await credential.validateAndUpdateFields(data.fields);
|
||||
|
||||
const response = apiResponse.successful(
|
||||
"Credential Fields Updated Successfully!",
|
||||
credential.toJson(),
|
||||
);
|
||||
return c.json(response, response.status as ContentfulStatusCode);
|
||||
},
|
||||
authMiddleware({
|
||||
permissions: ["credential.update", "credential.fields.update"],
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import * as credentialRoutes from "../credentials";
|
||||
|
||||
const credentialRouter = new Hono();
|
||||
Object.values(credentialRoutes).map((r) => credentialRouter.route("/", r));
|
||||
|
||||
export default credentialRouter;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Hono } from "hono";
|
||||
import * as credentialTypeRoutes from "../credential-types";
|
||||
|
||||
const credentialTypeRouter = new Hono();
|
||||
Object.values(credentialTypeRoutes).map((r) =>
|
||||
credentialTypeRouter.route("/", r),
|
||||
);
|
||||
|
||||
export default credentialTypeRouter;
|
||||
@@ -50,6 +50,8 @@ v1.route("/teapot", teapot);
|
||||
v1.route("/auth", require("./routers/authRouter").default);
|
||||
v1.route("/user", require("./routers/user").default);
|
||||
v1.route("/company", require("./routers/companyRouter").default);
|
||||
v1.route("/credential", require("./routers/credentialRouter").default);
|
||||
v1.route("/credential-type", require("./routers/credentialTypeRouter").default);
|
||||
app.route("/v1", v1);
|
||||
|
||||
export default app;
|
||||
|
||||
+9
-11
@@ -23,18 +23,16 @@ export const sessionDuration = 30 * 24 * 60 * 60000;
|
||||
export const accessTokenDuration = "10min";
|
||||
export const refreshTokenDuration = "30d";
|
||||
|
||||
export const accessTokenPrivateKey = readFileSync(
|
||||
`${import.meta.dir}/../.accessToken.key`,
|
||||
export const accessTokenPrivateKey =
|
||||
readFileSync(`.accessToken.key`).toString();
|
||||
export const refreshTokenPrivateKey =
|
||||
readFileSync(`.refreshToken.key`).toString();
|
||||
export const permissionsPrivateKey = readFileSync(`.permissions.key`);
|
||||
export const secureValuesPrivateKey =
|
||||
readFileSync(`.secureValues.key`).toString();
|
||||
export const secureValuesPublicKey = readFileSync(
|
||||
`public-keys/.secureValues.pub`,
|
||||
).toString();
|
||||
export const refreshTokenPrivateKey = readFileSync(
|
||||
`${import.meta.dir}/../.refreshToken.key`,
|
||||
).toString();
|
||||
export const permissionsPrivateKey = readFileSync(
|
||||
`${import.meta.dir}/../.permissions.key`,
|
||||
);
|
||||
export const apiKeyTokenPrivateKey = readFileSync(
|
||||
`${import.meta.dir}/../.apiKeyToken.key`,
|
||||
);
|
||||
|
||||
// Microsoft Auth Constants
|
||||
const msalConfig: msal.Configuration = {
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
import { z } from "zod";
|
||||
import {
|
||||
Credential,
|
||||
CredentialType,
|
||||
Company,
|
||||
SecureValue,
|
||||
} from "../../generated/prisma/client";
|
||||
import { prisma } from "../constants";
|
||||
import { fieldValidator } from "../modules/credentials/fieldValidator";
|
||||
import {
|
||||
CredentialField,
|
||||
CredentialTypeField,
|
||||
} from "../modules/credentials/credentialTypeDefs";
|
||||
import { generateSecureValue } from "../modules/credentials/generateSecureValue";
|
||||
import { readSecureValue } from "../modules/credentials/readSecureValue";
|
||||
import GenericError from "../Errors/GenericError";
|
||||
|
||||
/**
|
||||
* Credential Controller
|
||||
*
|
||||
* This class manages credential data, including field validation,
|
||||
* secure value storage/retrieval, and credential updates.
|
||||
*/
|
||||
export class CredentialController {
|
||||
public readonly id: string;
|
||||
public name: string;
|
||||
public readonly typeId: string;
|
||||
public readonly companyId: string;
|
||||
public fields: any;
|
||||
|
||||
private _type: CredentialType;
|
||||
private _company: Company;
|
||||
private _secureValues: SecureValue[];
|
||||
|
||||
public readonly createdAt: Date;
|
||||
public updatedAt: Date;
|
||||
|
||||
constructor(
|
||||
credentialData: Credential & {
|
||||
type: CredentialType;
|
||||
company: Company;
|
||||
securevalues: SecureValue[];
|
||||
},
|
||||
) {
|
||||
this.id = credentialData.id;
|
||||
this.name = credentialData.name;
|
||||
this.typeId = credentialData.typeId;
|
||||
this.companyId = credentialData.companyId;
|
||||
this.fields = credentialData.fields;
|
||||
this._type = credentialData.type;
|
||||
this._company = credentialData.company;
|
||||
this._secureValues = credentialData.securevalues;
|
||||
this.createdAt = credentialData.createdAt;
|
||||
this.updatedAt = credentialData.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Internal Values
|
||||
*
|
||||
* Internal method to update all internal values when we query the database.
|
||||
* This keeps everything up-to-date even when we pass around the credential controller.
|
||||
*
|
||||
* @param credentialData - Credential object from Prisma
|
||||
*/
|
||||
private _updateInternalValues(credentialData: Credential) {
|
||||
this.name = credentialData.name;
|
||||
this.fields = credentialData.fields;
|
||||
this.updatedAt = credentialData.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and Update Fields
|
||||
*
|
||||
* This method validates the submitted fields against the credential type's
|
||||
* acceptable fields, then updates the credential in the database.
|
||||
* Secure fields are encrypted and stored in the SecureValue table.
|
||||
*
|
||||
* @param fields - The fields to validate and update
|
||||
* @returns {Promise<CredentialController>} - The updated credential controller
|
||||
*/
|
||||
async validateAndUpdateFields(
|
||||
fields: CredentialField[],
|
||||
): Promise<CredentialController> {
|
||||
// Get acceptable fields from the credential type
|
||||
const acceptableFields = this._type.fields as any as CredentialTypeField[];
|
||||
// Validate the fields
|
||||
const validatedFields = await fieldValidator(fields, acceptableFields);
|
||||
|
||||
// Separate secure and non-secure fields
|
||||
const secureFields = validatedFields.filter((f) => f.secure);
|
||||
const nonSecureFields = validatedFields.filter((f) => !f.secure);
|
||||
|
||||
// Process secure fields - encrypt and store in SecureValue table
|
||||
await Promise.all(
|
||||
secureFields.map(async (field) => {
|
||||
const { encrypted, hash } = generateSecureValue(field.value);
|
||||
|
||||
// Check if a secure value already exists for this field
|
||||
const existingSecureValue = await prisma.secureValue.findFirst({
|
||||
where: {
|
||||
credentialId: this.id,
|
||||
name: field.fieldId,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingSecureValue) {
|
||||
// Update existing secure value
|
||||
await prisma.secureValue.update({
|
||||
where: { id: existingSecureValue.id },
|
||||
data: {
|
||||
content: encrypted,
|
||||
hash,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// Create new secure value
|
||||
await prisma.secureValue.create({
|
||||
data: {
|
||||
name: field.fieldId,
|
||||
content: encrypted,
|
||||
hash,
|
||||
credentialId: this.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Build fields object for non-secure fields
|
||||
const fieldsObject: Record<string, any> = {};
|
||||
nonSecureFields.forEach((field) => {
|
||||
fieldsObject[field.fieldId] = field.value;
|
||||
});
|
||||
|
||||
// Update the credential with non-secure fields
|
||||
const updatedCredential = await prisma.credential.update({
|
||||
where: { id: this.id },
|
||||
data: {
|
||||
fields: fieldsObject,
|
||||
},
|
||||
});
|
||||
|
||||
this._updateInternalValues(updatedCredential);
|
||||
|
||||
// Refresh secure values
|
||||
const secureValues = await prisma.secureValue.findMany({
|
||||
where: { credentialId: this.id },
|
||||
});
|
||||
this._secureValues = secureValues;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch All Field Values
|
||||
*
|
||||
* Returns all field values (both secure and non-secure) for this credential.
|
||||
* Secure field values are NOT decrypted - use `readSecureFieldValue` for that.
|
||||
*
|
||||
* @returns {Promise<CredentialField[]>} - Array of all fields with their encrypted values
|
||||
*/
|
||||
async fetchAllFieldValues(): Promise<CredentialField[]> {
|
||||
const fields: CredentialField[] = [];
|
||||
|
||||
// Add non-secure fields from the fields JSON
|
||||
const nonSecureFields = this.fields as Record<string, any>;
|
||||
Object.entries(nonSecureFields || {}).forEach(([fieldId, value]) => {
|
||||
fields.push({
|
||||
id: `${this.id}-${fieldId}`, // Generate a consistent ID
|
||||
fieldId,
|
||||
value: value as string,
|
||||
});
|
||||
});
|
||||
|
||||
// Add secure fields from SecureValue table (encrypted)
|
||||
this._secureValues.forEach((secureValue) => {
|
||||
fields.push({
|
||||
id: secureValue.id,
|
||||
fieldId: secureValue.name,
|
||||
value: secureValue.content, // Encrypted value
|
||||
});
|
||||
});
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Secure Field Value
|
||||
*
|
||||
* Decrypts and returns the value of a specific secure field.
|
||||
*
|
||||
* @param fieldId - The field ID to read
|
||||
* @returns {Promise<string>} - The decrypted field value
|
||||
*/
|
||||
async readSecureFieldValue(fieldId: string): Promise<string> {
|
||||
const secureValue = this._secureValues.find((sv) => sv.name === fieldId);
|
||||
|
||||
if (!secureValue) {
|
||||
throw new GenericError({
|
||||
message: `Secure field not found: ${fieldId}`,
|
||||
name: "SecureFieldNotFound",
|
||||
cause: `No secure value exists for field '${fieldId}' in credential '${this.id}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
// Decrypt the value
|
||||
const decryptedValue = readSecureValue(
|
||||
secureValue.content,
|
||||
secureValue.hash,
|
||||
);
|
||||
|
||||
return decryptedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read All Secure Values
|
||||
*
|
||||
* Decrypts and returns all secure field values for this credential.
|
||||
*
|
||||
* @returns {Promise<Record<string, string>>} - Object mapping field IDs to decrypted values
|
||||
*/
|
||||
async readAllSecureValues(): Promise<Record<string, string>> {
|
||||
const secureValues: Record<string, string> = {};
|
||||
|
||||
await Promise.all(
|
||||
this._secureValues.map(async (secureValue) => {
|
||||
const decryptedValue = readSecureValue(
|
||||
secureValue.content,
|
||||
secureValue.hash,
|
||||
);
|
||||
secureValues[secureValue.name] = decryptedValue;
|
||||
}),
|
||||
);
|
||||
|
||||
return secureValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Credential
|
||||
*
|
||||
* Update the credential name or other basic properties.
|
||||
*
|
||||
* @param data - Partial credential data to update
|
||||
* @returns {Promise<CredentialController>} - The updated credential controller
|
||||
*/
|
||||
async update(
|
||||
data: Partial<Pick<Credential, "name">>,
|
||||
): Promise<CredentialController> {
|
||||
const pData = z
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
})
|
||||
.strict()
|
||||
.parse(data);
|
||||
|
||||
const updatedCredential = await prisma.credential.update({
|
||||
where: { id: this.id },
|
||||
data: pData,
|
||||
});
|
||||
|
||||
this._updateInternalValues(updatedCredential);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Credential Type
|
||||
*
|
||||
* Returns the credential type information.
|
||||
*
|
||||
* @returns {CredentialType} - The credential type
|
||||
*/
|
||||
getType(): CredentialType {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Company
|
||||
*
|
||||
* Returns the company this credential belongs to.
|
||||
*
|
||||
* @returns {Company} - The company
|
||||
*/
|
||||
getCompany(): Company {
|
||||
return this._company;
|
||||
}
|
||||
|
||||
/**
|
||||
* To JSON
|
||||
*
|
||||
* Create an object that can be safely returned to the user.
|
||||
* Secure values are not included by default.
|
||||
*
|
||||
* @param opts - Options to change the output
|
||||
* @returns - An object that is JSON friendly
|
||||
*/
|
||||
toJson(opts?: { includeSecureValues?: boolean }) {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
typeId: this.typeId,
|
||||
companyId: this.companyId,
|
||||
fields: this.fields,
|
||||
type: {
|
||||
id: this._type.id,
|
||||
name: this._type.name,
|
||||
fields: this._type.fields,
|
||||
permissionScope: this._type.permissionScope,
|
||||
},
|
||||
company: {
|
||||
id: this._company.id,
|
||||
name: this._company.name,
|
||||
},
|
||||
secureFieldIds: opts?.includeSecureValues
|
||||
? this._secureValues.map((sv) => sv.name)
|
||||
: undefined,
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import { z } from "zod";
|
||||
import { CredentialType, Credential } from "../../generated/prisma/client";
|
||||
import { prisma } from "../constants";
|
||||
import { CredentialTypeField } from "../modules/credentials/credentialTypeDefs";
|
||||
import { CredentialController } from "./CredentialController";
|
||||
|
||||
/**
|
||||
* Credential Type Controller
|
||||
*
|
||||
* This class manages credential type data, including field definitions,
|
||||
* permission scopes, and associated credentials.
|
||||
*/
|
||||
export class CredentialTypeController {
|
||||
public readonly id: string;
|
||||
public name: string;
|
||||
public permissionScope: string;
|
||||
public icon: string | null;
|
||||
public fields: CredentialTypeField[];
|
||||
|
||||
private _credentials: Credential[];
|
||||
|
||||
public readonly createdAt: Date;
|
||||
public updatedAt: Date;
|
||||
|
||||
constructor(
|
||||
credentialTypeData: CredentialType & {
|
||||
credentials: Credential[];
|
||||
},
|
||||
) {
|
||||
this.id = credentialTypeData.id;
|
||||
this.name = credentialTypeData.name;
|
||||
this.permissionScope = credentialTypeData.permissionScope;
|
||||
this.icon = credentialTypeData.icon;
|
||||
this.fields = credentialTypeData.fields! as any as CredentialTypeField[];
|
||||
this._credentials = credentialTypeData.credentials;
|
||||
this.createdAt = credentialTypeData.createdAt;
|
||||
this.updatedAt = credentialTypeData.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Internal Values
|
||||
*
|
||||
* Internal method to update all internal values when we query the database.
|
||||
* This keeps everything up-to-date even when we pass around the credential type controller.
|
||||
*
|
||||
* @param credentialTypeData - CredentialType object from Prisma
|
||||
*/
|
||||
private _updateInternalValues(credentialTypeData: CredentialType) {
|
||||
this.name = credentialTypeData.name;
|
||||
this.permissionScope = credentialTypeData.permissionScope;
|
||||
this.icon = credentialTypeData.icon;
|
||||
this.fields = credentialTypeData.fields! as any as CredentialTypeField[];
|
||||
this.updatedAt = credentialTypeData.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Credential Type
|
||||
*
|
||||
* Update the credential type's name, permission scope, icon, or fields.
|
||||
*
|
||||
* @param data - Partial credential type data to update
|
||||
* @returns {Promise<CredentialTypeController>} - The updated credential type controller
|
||||
*/
|
||||
async update(
|
||||
data: Partial<
|
||||
Pick<CredentialType, "name" | "permissionScope" | "icon"> & {
|
||||
fields: CredentialTypeField[];
|
||||
}
|
||||
>,
|
||||
): Promise<CredentialTypeController> {
|
||||
const pData = z
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
permissionScope: z.string().optional(),
|
||||
icon: z.string().optional(),
|
||||
fields: z.array(z.any()).optional(),
|
||||
})
|
||||
.strict()
|
||||
.parse(data);
|
||||
|
||||
const updatedCredentialType = await prisma.credentialType.update({
|
||||
where: { id: this.id },
|
||||
data: pData,
|
||||
});
|
||||
|
||||
this._updateInternalValues(updatedCredentialType);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Field Definition
|
||||
*
|
||||
* Get the definition for a specific field by its ID.
|
||||
*
|
||||
* @param fieldId - The field ID to look up
|
||||
* @returns {CredentialTypeField | undefined} - The field definition or undefined
|
||||
*/
|
||||
getFieldDefinition(fieldId: string): CredentialTypeField | undefined {
|
||||
return this.fields.find((f) => f.id === fieldId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Required Fields
|
||||
*
|
||||
* Returns all fields that are marked as required.
|
||||
*
|
||||
* @returns {CredentialTypeField[]} - Array of required fields
|
||||
*/
|
||||
getRequiredFields(): CredentialTypeField[] {
|
||||
return this.fields.filter((f) => f.required);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Secure Fields
|
||||
*
|
||||
* Returns all fields that should be stored securely (encrypted).
|
||||
*
|
||||
* @returns {CredentialTypeField[]} - Array of secure fields
|
||||
*/
|
||||
getSecureFields(): CredentialTypeField[] {
|
||||
return this.fields.filter((f) => f.secure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch Credentials
|
||||
*
|
||||
* Fetch all credentials that use this credential type.
|
||||
*
|
||||
* @returns {Promise<CredentialController[]>} - Array of credential controllers
|
||||
*/
|
||||
async fetchCredentials(): Promise<CredentialController[]> {
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: { typeId: this.id },
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
});
|
||||
|
||||
return credentials.map((cred) => new CredentialController(cred));
|
||||
}
|
||||
|
||||
/**
|
||||
* Count Credentials
|
||||
*
|
||||
* Count how many credentials use this credential type.
|
||||
*
|
||||
* @returns {number} - Number of credentials using this type
|
||||
*/
|
||||
countCredentials(): number {
|
||||
return this._credentials.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* To JSON
|
||||
*
|
||||
* Create an object that can be safely returned to the user.
|
||||
*
|
||||
* @param opts - Options to change the output
|
||||
* @returns - An object that is JSON friendly
|
||||
*/
|
||||
toJson(opts?: { includeCredentialCount?: boolean }) {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
permissionScope: this.permissionScope,
|
||||
icon: this.icon,
|
||||
fields: this.fields,
|
||||
credentialCount: opts?.includeCredentialCount
|
||||
? this._credentials.length
|
||||
: undefined,
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import { prisma } from "../constants";
|
||||
import { CredentialTypeController } from "../controllers/CredentialTypeController";
|
||||
import { CredentialTypeField } from "../modules/credentials/credentialTypeDefs";
|
||||
import GenericError from "../Errors/GenericError";
|
||||
|
||||
export const credentialTypes = {
|
||||
/**
|
||||
* Fetch Credential Type
|
||||
*
|
||||
* Fetch a credential type by its ID or name and return a CredentialTypeController instance.
|
||||
*
|
||||
* @param identifier - The credential type ID or name to fetch
|
||||
* @returns {Promise<CredentialTypeController>} - The credential type controller
|
||||
*/
|
||||
async fetch(identifier: string): Promise<CredentialTypeController> {
|
||||
const credentialType = await prisma.credentialType.findFirst({
|
||||
where: {
|
||||
OR: [{ id: identifier }, { name: identifier }],
|
||||
},
|
||||
include: {
|
||||
credentials: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!credentialType) {
|
||||
throw new GenericError({
|
||||
message: "Credential type not found",
|
||||
name: "CredentialTypeNotFound",
|
||||
cause: `No credential type exists with identifier '${identifier}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
return new CredentialTypeController(credentialType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch All Credential Types
|
||||
*
|
||||
* Fetch all credential types in the system.
|
||||
*
|
||||
* @returns {Promise<CredentialTypeController[]>} - Array of credential type controllers
|
||||
*/
|
||||
async fetchAll(): Promise<CredentialTypeController[]> {
|
||||
const credentialTypesList = await prisma.credentialType.findMany({
|
||||
include: {
|
||||
credentials: true,
|
||||
},
|
||||
});
|
||||
|
||||
return credentialTypesList.map((ct) => new CredentialTypeController(ct));
|
||||
},
|
||||
|
||||
/**
|
||||
* Create Credential Type
|
||||
*
|
||||
* Create a new credential type with its field definitions.
|
||||
*
|
||||
* @param data - The credential type data to create
|
||||
* @returns {Promise<CredentialTypeController>} - The created credential type controller
|
||||
*/
|
||||
async create(data: {
|
||||
name: string;
|
||||
permissionScope: string;
|
||||
fields: CredentialTypeField[];
|
||||
icon?: string;
|
||||
}): Promise<CredentialTypeController> {
|
||||
// Check if a credential type with this name already exists
|
||||
const existing = await prisma.credentialType.findFirst({
|
||||
where: { name: data.name },
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
throw new GenericError({
|
||||
message: "Credential type name already exists",
|
||||
name: "CredentialTypeAlreadyExists",
|
||||
cause: `A credential type with name '${data.name}' already exists`,
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const credentialType = await prisma.credentialType.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
permissionScope: data.permissionScope,
|
||||
fields: data.fields as any,
|
||||
icon: data.icon,
|
||||
},
|
||||
include: {
|
||||
credentials: true,
|
||||
},
|
||||
});
|
||||
|
||||
return new CredentialTypeController(credentialType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete Credential Type
|
||||
*
|
||||
* Delete a credential type by its ID.
|
||||
* This will cascade delete all credentials of this type.
|
||||
*
|
||||
* @param id - The credential type ID to delete
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.credentialType.delete({
|
||||
where: { id },
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,158 @@
|
||||
import { prisma } from "../constants";
|
||||
import { CredentialController } from "../controllers/CredentialController";
|
||||
import { fieldValidator } from "../modules/credentials/fieldValidator";
|
||||
import {
|
||||
CredentialField,
|
||||
CredentialTypeField,
|
||||
} from "../modules/credentials/credentialTypeDefs";
|
||||
import { generateSecureValue } from "../modules/credentials/generateSecureValue";
|
||||
import GenericError from "../Errors/GenericError";
|
||||
|
||||
export const credentials = {
|
||||
/**
|
||||
* Fetch Credential
|
||||
*
|
||||
* Fetch a credential by its ID and return a CredentialController instance.
|
||||
*
|
||||
* @param id - The credential ID to fetch
|
||||
* @returns {Promise<CredentialController>} - The credential controller
|
||||
*/
|
||||
async fetch(id: string): Promise<CredentialController> {
|
||||
const credential = await prisma.credential.findFirst({
|
||||
where: { id },
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!credential) {
|
||||
throw new GenericError({
|
||||
message: "Credential not found",
|
||||
name: "CredentialNotFound",
|
||||
cause: `No credential exists with ID '${id}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
return new CredentialController(credential);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch Credentials by Company
|
||||
*
|
||||
* Fetch all credentials associated with a specific company.
|
||||
*
|
||||
* @param companyId - The company ID to fetch credentials for
|
||||
* @returns {Promise<CredentialController[]>} - Array of credential controllers
|
||||
*/
|
||||
async fetchByCompany(companyId: string): Promise<CredentialController[]> {
|
||||
const credentialsList = await prisma.credential.findMany({
|
||||
where: { companyId },
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
});
|
||||
|
||||
return credentialsList.map((cred) => new CredentialController(cred));
|
||||
},
|
||||
|
||||
/**
|
||||
* Create Credential
|
||||
*
|
||||
* Create a new credential with validated fields.
|
||||
* This method processes all incoming field values, validating them against
|
||||
* the credential type, encrypting secure fields, and inserting everything
|
||||
* into the database atomically.
|
||||
*
|
||||
* @param data - The credential data to create
|
||||
* @returns {Promise<CredentialController>} - The created credential controller
|
||||
*/
|
||||
async create(data: {
|
||||
name: string;
|
||||
typeId: string;
|
||||
companyId: string;
|
||||
fields: CredentialField[];
|
||||
}): Promise<CredentialController> {
|
||||
// Fetch the credential type to get acceptable fields
|
||||
const credentialType = await prisma.credentialType.findFirst({
|
||||
where: { id: data.typeId },
|
||||
});
|
||||
|
||||
if (!credentialType) {
|
||||
throw new GenericError({
|
||||
message: "Credential type not found",
|
||||
name: "CredentialTypeNotFound",
|
||||
cause: `No credential type exists with ID '${data.typeId}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
// Validate the fields against acceptable fields
|
||||
const acceptableFields = JSON.parse(credentialType.fields! as string).map(
|
||||
(f: { id: string; name: string; secure: boolean }) => ({
|
||||
id: f.id,
|
||||
name: f.name,
|
||||
secure: f.secure,
|
||||
}),
|
||||
) as CredentialTypeField[];
|
||||
const validatedFields = await fieldValidator(data.fields, acceptableFields);
|
||||
|
||||
// Separate secure and non-secure fields
|
||||
const secureFields = validatedFields.filter((f) => f.secure);
|
||||
const nonSecureFields = validatedFields.filter((f) => !f.secure);
|
||||
|
||||
// Build fields object for non-secure fields
|
||||
const fieldsObject: Record<string, any> = {};
|
||||
nonSecureFields.forEach((field) => {
|
||||
fieldsObject[field.fieldId] = field.value;
|
||||
});
|
||||
|
||||
// Encrypt secure field values
|
||||
const secureValueData = secureFields.map((field) => {
|
||||
const { encrypted, hash } = generateSecureValue(field.value);
|
||||
return {
|
||||
name: field.fieldId,
|
||||
content: encrypted,
|
||||
hash,
|
||||
};
|
||||
});
|
||||
|
||||
// Create credential and all secure values in a transaction
|
||||
const credential = await prisma.credential.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
typeId: data.typeId,
|
||||
companyId: data.companyId,
|
||||
fields: fieldsObject,
|
||||
securevalues: {
|
||||
create: secureValueData,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
});
|
||||
|
||||
return new CredentialController(credential);
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete Credential
|
||||
*
|
||||
* Delete a credential by its ID.
|
||||
*
|
||||
* @param id - The credential ID to delete
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(id: string): Promise<void> {
|
||||
await prisma.credential.delete({
|
||||
where: { id },
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
export enum ValueType {
|
||||
PLAIN_TEXT = "plain_text",
|
||||
PASSWORD = "password",
|
||||
}
|
||||
|
||||
export interface CredentialTypeField {
|
||||
id: string; // I.e. "clientId", "clientSecret", etc.
|
||||
name: string; // I.e. "Client ID", "Client Secret", etc.
|
||||
required: boolean;
|
||||
secure: boolean; // Whether this field should be stored encrypted in the database
|
||||
valueType: ValueType; // For future extensibility, currently all fields are strings
|
||||
}
|
||||
|
||||
export interface CredentialField {
|
||||
id: string; // CUID
|
||||
fieldId: string; // I.e. "clientId", "clientSecret", etc.
|
||||
value: string; // Encrypted value stored in the database
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Collection } from "@discordjs/collection";
|
||||
import { CredentialField, CredentialTypeField } from "./credentialTypeDefs";
|
||||
import GenericError from "../../Errors/GenericError";
|
||||
|
||||
/**
|
||||
* Field Validator
|
||||
*
|
||||
* This method will take a record of the fields being submitted and compare them against a record of the acceptable fields
|
||||
* for a credential type. If any of the submitted fields do not match an acceptable field, an error will be thrown.
|
||||
*
|
||||
* If all the credentials pass, it will return a processed version of the submitted fields including fields that need to be
|
||||
* stored securely (encrypted) and fields that do not.
|
||||
*
|
||||
* @param fields - The fields in object form that are being submitted.
|
||||
* @param acceptableFields - The acceptable field to be compared against.
|
||||
*/
|
||||
export const fieldValidator = async (
|
||||
fields: CredentialField[],
|
||||
acceptableFields: CredentialTypeField[],
|
||||
): Promise<
|
||||
{
|
||||
id: string;
|
||||
fieldId: string;
|
||||
value: string;
|
||||
secure: boolean;
|
||||
}[]
|
||||
> => {
|
||||
const afCollection = new Collection(acceptableFields.map((f) => [f.id, f]));
|
||||
|
||||
await Promise.all(
|
||||
fields.map(async (field) => {
|
||||
const matchingField = afCollection.get(field.fieldId);
|
||||
if (!matchingField) {
|
||||
throw new GenericError({
|
||||
message: `Invalid field ID: ${field.fieldId}`,
|
||||
name: "InvalidCredentialField",
|
||||
cause: `No acceptable field with ID '${field.fieldId}' found.`,
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}),
|
||||
);
|
||||
|
||||
return fields.map((field) => {
|
||||
const matchingField = afCollection.get(field.fieldId)!;
|
||||
|
||||
return {
|
||||
id: field.id,
|
||||
fieldId: field.fieldId,
|
||||
value: field.value,
|
||||
secure: matchingField.secure,
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import Password from "../tools/Password";
|
||||
import crypto from "crypto";
|
||||
import { secureValuesPublicKey } from "../../constants";
|
||||
|
||||
export const generateSecureValue = (content: string) => {
|
||||
// Generate a hash of the content
|
||||
const hash = Password.hash(content);
|
||||
|
||||
// Encrypt the content using the .secureValues.pub public key
|
||||
const encrypted = crypto.publicEncrypt(
|
||||
{
|
||||
key: secureValuesPublicKey,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
oaepHash: "sha256",
|
||||
},
|
||||
Buffer.from(content, "utf-8"),
|
||||
);
|
||||
|
||||
// Return the encrypted content and the hash for storage
|
||||
return {
|
||||
encrypted: encrypted.toString("base64"),
|
||||
hash,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import Password from "../tools/Password";
|
||||
import crypto from "crypto";
|
||||
import { secureValuesPrivateKey } from "../../constants";
|
||||
|
||||
export const readSecureValue = (
|
||||
encryptedContent: string,
|
||||
hash?: string,
|
||||
): string => {
|
||||
// Decrypt the content using the .secureValues.key private key
|
||||
const decrypted = crypto.privateDecrypt(
|
||||
{
|
||||
key: secureValuesPrivateKey,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
oaepHash: "sha256",
|
||||
},
|
||||
Buffer.from(encryptedContent, "base64"),
|
||||
);
|
||||
|
||||
const content = decrypted.toString("utf-8");
|
||||
|
||||
// Optionally validate the hash if provided
|
||||
if (hash) {
|
||||
const isValid = Password.validate(content, hash);
|
||||
if (!isValid) {
|
||||
throw new Error("Secure value hash validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
@@ -10,7 +10,10 @@ export default class Password {
|
||||
|
||||
public static hash(password: string, options?: HashPasswordOptions): string {
|
||||
const salt =
|
||||
options?.overrideSalt ?? Password.generateSalt(options?.saltOpts);
|
||||
options?.overrideSalt ??
|
||||
(options?.saltOpts?.length
|
||||
? Password.generateSalt(options?.saltOpts)
|
||||
: "");
|
||||
const hash = blake2sHex(`$BLAKE2s$${password}$${salt}`);
|
||||
return `BLAKE2s$${hash}$${salt}`;
|
||||
}
|
||||
@@ -19,7 +22,7 @@ export default class Password {
|
||||
const [algo, oldHash, salt] = hashed.split(/\$/g);
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(hashed),
|
||||
Buffer.from(Password.hash(newPass, { overrideSalt: salt }))
|
||||
Buffer.from(Password.hash(newPass, { overrideSalt: salt })),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+41
-22
@@ -7,31 +7,50 @@ This script will go through and genrate all the keys necessary for running the C
|
||||
This process might take several minutes.
|
||||
-----------------`);
|
||||
|
||||
await Promise.all(
|
||||
[
|
||||
".accessToken.key",
|
||||
".refreshToken.key",
|
||||
".permissions.key",
|
||||
".apiKeyToken.key",
|
||||
].map(async (v) => {
|
||||
if (
|
||||
await Bun.file(v)
|
||||
.exists()
|
||||
.then((bool) => {
|
||||
if (bool) {
|
||||
console.log(`'${v}' already exists`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
) {
|
||||
console.log(`Generating '${v}'...`);
|
||||
const keys = keypair({ bits: 4096 });
|
||||
const keyFiles = [
|
||||
".accessToken.key",
|
||||
".refreshToken.key",
|
||||
".permissions.key",
|
||||
".secureValues.key",
|
||||
];
|
||||
|
||||
await Bun.write(v, keys.private);
|
||||
const publicDir = "public-keys";
|
||||
|
||||
await Promise.all(
|
||||
keyFiles.map(async (v) => {
|
||||
const privExists = await Bun.file(v)
|
||||
.exists()
|
||||
.then((bool) => {
|
||||
if (bool) {
|
||||
console.log(`'${v}' already exists`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const pubPath = `${publicDir}/${v.replace(/\.key$/, ".pub")}`;
|
||||
const pubExists = await Bun.file(pubPath)
|
||||
.exists()
|
||||
.then((bool) => {
|
||||
if (bool) {
|
||||
console.log(`'${pubPath}' already exists`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!privExists || !pubExists) {
|
||||
console.log(`Generating '${v}' and '${pubPath}'...`);
|
||||
const keys = keypair({ bits: 4096 });
|
||||
if (!privExists) {
|
||||
await Bun.write(v, keys.private);
|
||||
}
|
||||
if (!pubExists) {
|
||||
await Bun.write(pubPath, keys.public);
|
||||
}
|
||||
}
|
||||
return;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
console.log("\nGenerated All Keys Successfully!");
|
||||
|
||||
Reference in New Issue
Block a user