CREDENTIAL TYPE MANAGEMENT WORKS

This commit is contained in:
2026-02-14 15:15:49 -06:00
parent b7637334a6
commit cdae4d47a4
46 changed files with 7621 additions and 41 deletions
+981
View File
@@ -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.
+5
View File
@@ -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=="],
+15
View File
@@ -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
+15
View File
@@ -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
+75
View File
@@ -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
}
+32 -2
View File
@@ -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 {
+299 -2
View File
@@ -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]
+3
View File
@@ -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'
+183 -1
View File
@@ -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
+1
View File
@@ -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",
+48
View File
@@ -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
}
+43
View File
@@ -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"] }),
);
+23
View File
@@ -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"] }),
);
+25
View File
@@ -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"] }),
);
+25
View File
@@ -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"],
}),
);
+15
View File
@@ -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,
};
+46
View File
@@ -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"] }),
);
+41
View File
@@ -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"] }),
);
+23
View File
@@ -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"] }),
);
+23
View File
@@ -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"] }),
);
+25
View File
@@ -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"] }),
);
+26
View File
@@ -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"],
}),
);
+19
View File
@@ -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,
};
+26
View File
@@ -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"],
}),
);
+33
View File
@@ -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"] }),
);
+41
View File
@@ -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"],
}),
);
+7
View File
@@ -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;
+9
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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 = {
+322
View File
@@ -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,
};
}
}
+178
View File
@@ -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,
};
}
}
+111
View File
@@ -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 },
});
},
};
+158
View File
@@ -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
}
+56
View File
@@ -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;
};
+5 -2
View File
@@ -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
View File
@@ -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!");