Skip to content

Secrets API

Управление секретами интеграций. Секреты хранятся в D1 базе данных integ-db в таблице creds в зашифрованном виде.

Архитектура

Секреты - это высокоуровневый API для управления чувствительной информацией интеграций с фильтрацией по интеграции.

Admin UI
   |
   v
/api/core/secrets (GET, POST, PATCH, DELETE)
   |
   v
SecretsService (высокоуровневая логика)
   |
   v
CryptoService (AES-256-GCM + PBKDF2)
   |
   v
D1 Database (integ-db.creds table)

Шифрование

Секреты шифруются с использованием единого алгоритма, совместимого с integ-core:

ПараметрЗначение
АлгоритмAES-256-GCM
Key derivationPBKDF2 (100,000 итераций, SHA-256)
IV длина12 байт
Формат{iv_base64}.{data_base64}

Переменные окружения (Doppler):

  • CRYPTO_KEY — мастер-ключ шифрования
  • CRYPTO_SALT — соль для PBKDF2

ВАЖНО

Данные, зашифрованные в integ-core (Cloudflare Workers), могут быть расшифрованы в integ-api (NestJS) и наоборот, при условии использования одинаковых CRYPTO_KEY и CRYPTO_SALT.

Таблица структура

sql
CREATE TABLE creds (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  integration_name TEXT NOT NULL,    -- 'sofa', 'rozetka', 'promua'
  key TEXT NOT NULL,                 -- 'NETHUNT_API_KEY', 'KEYCRM_API_KEY'
  encrypted_value TEXT NOT NULL,     -- зашифровано CryptoService
  created_at TEXT DEFAULT (datetime('now')),
  updated_at TEXT DEFAULT (datetime('now')),

  UNIQUE(integration_name, key)
);

CREATE INDEX idx_creds_integration ON creds(integration_name);

Эндпоинты

GET /api/core/secrets

Получить все секреты.

Query Parameters:

  • integration (optional) - фильтр по названию интеграции

Request:

http
GET /api/core/secrets
Authorization: Bearer <token>

или с фильтром:

http
GET /api/core/secrets?integration=sofa
Authorization: Bearer <token>

Response (200 OK):

json
[
	{
		"id": 1,
		"integration": "sofa",
		"key": "NETHUNT_API_KEY",
		"encryptedValue": "****...****",
		"createdAt": "2024-01-01T00:00:00.000Z",
		"updatedAt": "2024-01-01T00:00:00.000Z"
	}
]

GET /api/core/secrets/:id

Получить секрет по ID.

Request:

http
GET /api/core/secrets/1
Authorization: Bearer <token>

Response (200 OK):

json
{
	"id": 1,
	"integration": "sofa",
	"key": "NETHUNT_API_KEY",
	"encryptedValue": "****...****",
	"createdAt": "2024-01-01T00:00:00.000Z",
	"updatedAt": "2024-01-01T00:00:00.000Z"
}

GET /api/core/secrets/:id/value

Получить расшифрованное значение секрета.

Request:

http
GET /api/core/secrets/1/value
Authorization: Bearer <token>

Response (200 OK):

json
{
	"value": "actual-api-key-value"
}

БЕЗОПАСНОСТЬ

Значение расшифровывается на сервере. Клиент получает реальное значение только при явном запросе через этот endpoint с /value.

POST /api/core/secrets

Создать новый секрет.

Request:

http
POST /api/core/secrets
Authorization: Bearer <token>
Content-Type: application/json

{
  "integration": "sofa",
  "key": "NETHUNT_API_KEY",
  "value": "your-api-key-value"
}

Response (201 Created):

json
{
	"id": 1,
	"integration": "sofa",
	"key": "NETHUNT_API_KEY",
	"encryptedValue": "****...****",
	"createdAt": "2024-01-01T00:00:00.000Z",
	"updatedAt": "2024-01-01T00:00:00.000Z"
}

PATCH /api/core/secrets/:id

Обновить значение секрета.

Request:

http
PATCH /api/core/secrets/1
Authorization: Bearer <token>
Content-Type: application/json

{
  "value": "new-api-key-value"
}

Response (200 OK):

json
{
	"id": 1,
	"integration": "sofa",
	"key": "NETHUNT_API_KEY",
	"encryptedValue": "****...****",
	"createdAt": "2024-01-01T00:00:00.000Z",
	"updatedAt": "2024-01-02T10:30:00.000Z"
}

DELETE /api/core/secrets/:id

Удалить секрет.

Request:

http
DELETE /api/core/secrets/1
Authorization: Bearer <token>

Response (200 OK):

json
{
	"success": true
}

POST /api/core/secrets/decrypt

Расшифровать произвольное зашифрованное значение. Используется для отладки и интеграции с integ-admin.

Request:

http
POST /api/core/secrets/decrypt
Authorization: Bearer <token>
Content-Type: application/json

{
  "encryptedValue": "base64iv.base64data"
}

Response (200 OK):

json
{
	"value": "decrypted-secret-value"
}

Использование

Этот endpoint полезен для расшифровки данных, зашифрованных в integ-core (Cloudflare Workers), без необходимости знать исходный ключ интеграции.

Пример использования

typescript
import axios from "axios";

const api = axios.create({
	baseURL: "http://localhost:3000/api",
	headers: {
		Authorization: `Bearer ${token}`
	}
});

async function manageSecrets() {
	// 1. Получить все секреты
	const { data: allSecrets } = await api.get("/core/secrets");
	console.log("All secrets:", allSecrets);

	// 2. Получить секреты конкретной интеграции
	const { data: sofaSecrets } = await api.get("/core/secrets?integration=sofa");
	console.log("Sofa secrets:", sofaSecrets);

	// 3. Создать новый секрет
	const { data: newSecret } = await api.post("/core/secrets", {
		integration: "sofa",
		key: "NETHUNT_API_KEY",
		value: "your-secret-value"
	});
	console.log("Created:", newSecret);

	// 4. Получить информацию о секрете по ID (замаскированное значение)
	const { data: secretInfo } = await api.get(`/core/secrets/${newSecret.id}`);
	console.log("Secret info:", secretInfo);

	// 5. Получить расшифрованное значение
	const { data: secretValue } = await api.get(`/core/secrets/${newSecret.id}/value`);
	console.log("Decrypted value:", secretValue.value);

	// 6. Обновить значение
	const { data: updated } = await api.patch(`/core/secrets/${newSecret.id}`, {
		value: "new-secret-value"
	});
	console.log("Updated:", updated);

	// 7. Удалить секрет
	await api.delete(`/core/secrets/${newSecret.id}`);
	console.log("Deleted");

	// 8. Расшифровать произвольное значение (для integ-admin)
	const { data: decrypted } = await api.post("/core/secrets/decrypt", {
		encryptedValue: "base64iv.base64encrypteddata"
	});
	console.log("Decrypted:", decrypted.value);
}

Дополнительно