Izstrādātājiem & AI

Vairogs API & MCP

Piekļūstiet sava seifa saturam programmatiski ar zero-knowledge šifrēšanu.

Lasīšana (Read)

GET

Kā iegūt un atšifrēt seifa vienumus ar Tag API v2

Tag API v2 nodrošina pilnu lasīšanas funkcionalitāti ar automātisku atšifrēšanu klienta pusē. Serveris atgriež šifrētus datus, ko jūs atšifrējat ar savu Decryption Key.

Pirms sākat

Pārliecinieties, ka esat izlasījis Autentifikācijas un Drošības sadaļas, lai saprastu atslēgu sistēmu un šifrēšanas principus.

GET/api/v2/tag/info

Atgriež pamatinformāciju par tagu un lietotāja publisko atslēgu.

Headers

ParametrsTipsApraksts
X-API-Key*stringAccess Key (vgtk_a_xxx)

Atbilde

json
{
  "success": true,
  "data": {
    "tagId": "tag_abc123",
    "tagName": "Mani MCP Dati",
    "userPublicKey": "base64_encoded_public_key",
    "mcpPublicKey": "base64_encoded_mcp_public_key",
    "itemCount": 42,
    "permissions": ["vault:read", "items:read", "items:write", "items:delete"]
  }
}

userPublicKey

userPublicKey ir galvenā lietotāja publiskā atslēga. To izmanto, lai izveidotu key slots, kas ļauj lietotājam atšifrēt datus ar savu master password.

GET/api/v2/tag/items

Atgriež visus šifrētos vienumus, kas saistīti ar tagu.

Headers

ParametrsTipsApraksts
X-API-Key*stringAccess Key (vgtk_a_xxx)

Query Parametri

ParametrsTipsApraksts
typestringFiltrēt pēc tipa: PASSWORD, NOTE, TOTP, IMAGE, DOCUMENT
limitnumberMaksimālais vienumu skaits (noklusējums: 100)
offsetnumberPāriešana (pagination)

Atbilde

json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "item_abc123",
        "type": "PASSWORD",
        "title": "GitHub Login",
        "encryptedData": "base64_encrypted_data",
        "iv": "base64_iv",
        "keySlots": [
          {
            "keyId": "main",
            "encryptedDEK": "base64_encrypted_dek",
            "nonce": "base64_nonce",
            "senderPublicKey": "base64_sender_public_key"
          },
          {
            "keyId": "vgtk_a_xxxxxxx",
            "encryptedDEK": "base64_encrypted_dek",
            "nonce": "base64_nonce",
            "senderPublicKey": "base64_sender_public_key"
          }
        ],
        "labels": ["tag_abc123"],
        "createdAt": "2024-01-15T12:00:00Z",
        "updatedAt": "2024-01-15T12:00:00Z"
      }
    ],
    "total": 42,
    "hasMore": true
  }
}

Atšifrēšanas Process

1

Atvasini keypair no Decrypt Key

PBKDF2(decryptKey, salt, 100000) → NaCl keypair

2

Atrodi savu Key Slot

Meklē keySlot ar keyId = pirmie 15 simboli no Access Key

3

Atšifrē DEK ar NaCl box.open

nacl.box.open(encryptedDEK, nonce, senderPublicKey, secretKey)

4

Atšifrē datus ar AES-GCM

AES-256-GCM decrypt(encryptedData, DEK, IV)

typescript
import nacl from 'tweetnacl'
import crypto from 'crypto'

const ACCESS_KEY = 'vgtk_a_xxxxxxxxxxxxxxxxxxxxx'
const DECRYPT_KEY = 'vgtk_d_xxxxxxxxxxxxxxxxxxxxx'
const MCP_SALT = 'vairogs-mcp-key-derivation-v1'

// 1. Atvasini keypair
function deriveKeypair(decryptKey: string) {
  const seed = crypto.pbkdf2Sync(decryptKey, MCP_SALT, 100000, 32, 'sha256')
  return nacl.box.keyPair.fromSecretKey(new Uint8Array(seed))
}

// 2. Utilītas
function base64ToUint8Array(base64: string) {
  return new Uint8Array(Buffer.from(base64, 'base64'))
}

// 3. Atšifrē vienumu
function decryptItem(item: any, keypair: nacl.BoxKeyPair) {
  // Atrodi pareizo key slot
  const mcpKeyPrefix = ACCESS_KEY.substring(0, 15)
  const keySlot = item.keySlots.find((s: any) => s.keyId === mcpKeyPrefix)

  if (!keySlot) throw new Error('Key slot not found')

  // Atšifrē DEK
  const encryptedDEK = base64ToUint8Array(keySlot.encryptedDEK)
  const nonce = base64ToUint8Array(keySlot.nonce)
  const senderPublicKey = base64ToUint8Array(keySlot.senderPublicKey)

  const dek = nacl.box.open(encryptedDEK, nonce, senderPublicKey, keypair.secretKey)
  if (!dek) throw new Error('Failed to decrypt DEK')

  // Atšifrē datus ar AES-GCM
  const iv = base64ToUint8Array(item.iv)
  const encryptedData = base64ToUint8Array(item.encryptedData)

  const authTag = encryptedData.slice(-16)
  const ciphertext = encryptedData.slice(0, -16)

  const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(dek), iv)
  decipher.setAuthTag(authTag)

  const decrypted = Buffer.concat([
    decipher.update(ciphertext),
    decipher.final()
  ])

  return JSON.parse(decrypted.toString('utf8'))
}

// Izmantošana
async function main() {
  const keypair = deriveKeypair(DECRYPT_KEY)

  const response = await fetch('https://vairogs.lv/api/v2/tag/items', {
    headers: { 'X-API-Key': ACCESS_KEY }
  })

  const { data } = await response.json()

  for (const item of data.items) {
    const decryptedData = decryptItem(item, keypair)
    console.log(`${item.title}:`, decryptedData)
  }
}

Vienumu Tipi & Struktūra

PASSWORD

json
{
  "username": "user@example.com",
  "password": "secret123",
  "url": "https://example.com",
  "notes": "Papildu piezīmes"
}

NOTE

json
{
  "content": "Piezīmes teksts..."
}

TOTP

json
{
  "secret": "JBSWY3DPEHPK3PXP",
  "issuer": "GitHub",
  "account": "user@example.com",
  "algorithm": "SHA1",
  "digits": 6,
  "period": 30
}

IMAGE / DOCUMENT

json
{
  "notes": "Apraksts",
  "fileMetadata": {
    "storagePath": "path/to/file",
    "thumbnailPath": "path/to/thumb",
    "originalFileName": "doc.pdf",
    "mimeType": "application/pdf",
    "fileSize": 102400
  }
}

SDK Piemērs

Ar @vairogs/sdk atšifrēšana notiek automātiski:

typescript
import { VairogsClient } from '@vairogs/sdk'

const client = new VairogsClient({
  accessKey: 'vgtk_a_xxx',
  decryptionKey: 'vgtk_d_xxx'
})

// Get all items (already decrypted!)
const items = await client.getItems()

// Filter by type
const passwords = await client.getItems({ type: 'PASSWORD' })

// Get specific item
const item = await client.getItem('item_abc123')