Piekļūstiet sava seifa saturam programmatiski ar zero-knowledge šifrēšanu.
Kā izveidot, atjaunināt un dzēst vienumus ar Tag API v2
Tag API v2 atbalsta pilnu CRUD funkcionalitāti. Visi jaunie vienumi tiek šifrēti klienta pusē pirms nosūtīšanas serverim, nodrošinot zero-knowledge arhitektūru.
Svarīgi
Rakstīšanas operācijām dati jāšifrē pirms nosūtīšanas. Jāizveido gan šifrētie dati, gan key slots galvenajam lietotājam un MCP atslēgai.
32 baitu gadījuma atslēga ar crypto.randomBytes(32)
JSON.stringify(data) → AES-256-GCM ar jaunu DEK un gadījuma IV
Šifrē DEK ar NaCl box gan galvenajam lietotājam (userPublicKey), gan MCP atslēgai
POST ar encryptedData, iv, keySlots un metadatiem
import nacl from 'tweetnacl'
import crypto from 'crypto'
// Utilītas
function generateDEK() {
return crypto.randomBytes(32)
}
function aesEncrypt(data: any, dek: Buffer) {
const iv = crypto.randomBytes(12)
const cipher = crypto.createCipheriv('aes-256-gcm', dek, iv)
const encrypted = Buffer.concat([
cipher.update(JSON.stringify(data)),
cipher.final()
])
const authTag = cipher.getAuthTag()
return {
encryptedData: Buffer.concat([encrypted, authTag]).toString('base64'),
iv: iv.toString('base64')
}
}
function createKeySlot(dek: Buffer, recipientPublicKey: Uint8Array, senderKeypair: nacl.BoxKeyPair) {
const nonce = nacl.randomBytes(24)
const encryptedDEK = nacl.box(
new Uint8Array(dek),
nonce,
recipientPublicKey,
senderKeypair.secretKey
)
return {
encryptedDEK: Buffer.from(encryptedDEK).toString('base64'),
nonce: Buffer.from(nonce).toString('base64'),
senderPublicKey: Buffer.from(senderKeypair.publicKey).toString('base64')
}
}
// Jauna vienuma izveidošana
async function createItem(
type: string,
title: string,
data: any,
tagId: string,
userPublicKey: Uint8Array,
mcpKeypair: nacl.BoxKeyPair,
accessKey: string
) {
// 1. Ģenerē DEK
const dek = generateDEK()
// 2. Šifrē datus
const { encryptedData, iv } = aesEncrypt(data, dek)
// 3. Izveido key slots
const mcpKeyPrefix = accessKey.substring(0, 15)
const keySlots = [
{ keyId: 'main', ...createKeySlot(dek, userPublicKey, mcpKeypair) },
{ keyId: mcpKeyPrefix, ...createKeySlot(dek, mcpKeypair.publicKey, mcpKeypair) }
]
// 4. Nosūta serverim
const response = await fetch('https://vairogs.lv/api/v2/tag/items', {
method: 'POST',
headers: {
'X-API-Key': accessKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
type,
title,
encryptedData,
iv,
labels: [tagId],
keySlots
})
})
return response.json()
}/api/v2/tag/itemsIzveido jaunu šifrētu vienumu.
| Parametrs | Tips | Apraksts |
|---|---|---|
X-API-Key* | string | Access Key (vgtk_a_xxx) |
Content-Type* | string | application/json |
| Parametrs | Tips | Apraksts |
|---|---|---|
type* | string | PASSWORD, NOTE, TOTP, IMAGE, DOCUMENT |
title* | string | Vienuma nosaukums (nav šifrēts) |
encryptedData* | string | Base64 šifrētie dati |
iv* | string | Base64 inicializācijas vektors |
labels* | string[] | Tag IDs masīvs |
keySlots* | array | Key slots masīvs |
interface KeySlot {
keyId: string // 'main' vai MCP key prefix (pirmie 15 simboli)
encryptedDEK: string // Base64 šifrētais DEK
nonce: string // Base64 NaCl nonce (24 baiti)
senderPublicKey: string // Base64 sūtītāja publiskā atslēga
}{
"success": true,
"data": {
"id": "item_newxyz123",
"type": "PASSWORD",
"title": "New Login",
"createdAt": "2024-01-15T12:00:00Z"
}
}/api/v2/tag/items/:idAtjaunina esošu vienumu. Jānosūta pilni jaunie šifrētie dati.
| Parametrs | Tips | Apraksts |
|---|---|---|
id* | string | Item ID |
| Parametrs | Tips | Apraksts |
|---|---|---|
title | string | Jauns nosaukums |
encryptedData* | string | Base64 šifrētie dati |
iv* | string | Base64 inicializācijas vektors |
keySlots* | array | Key slots masīvs |
Atceries
Atjauninot vienumu, vienmēr ģenerē jaunu DEK un jaunu IV. Nekad neizmanto tos pašus kriptogrāfiskos parametrus.
// Atjaunināt vienumu
async function updateItem(itemId: string, newData: any, ...) {
// Ģenerē JAUNU DEK un IV
const dek = generateDEK()
const { encryptedData, iv } = aesEncrypt(newData, dek)
// Izveido JAUNUS key slots
const keySlots = [
{ keyId: 'main', ...createKeySlot(dek, userPublicKey, mcpKeypair) },
{ keyId: mcpKeyPrefix, ...createKeySlot(dek, mcpKeypair.publicKey, mcpKeypair) }
]
const response = await fetch(`https://vairogs.lv/api/v2/tag/items/${itemId}`, {
method: 'PUT',
headers: {
'X-API-Key': accessKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
encryptedData,
iv,
keySlots
})
})
return response.json()
}/api/v2/tag/items/:idDzēš vienumu neatgriezeniski.
| Parametrs | Tips | Apraksts |
|---|---|---|
id* | string | Item ID |
{
"success": true,
"message": "Item deleted successfully"
}Brīdinājums
Dzēšana ir neatgriezeniska. Vienums un visi ar to saistītie faili tiks pilnībā dzēsti no sistēmas.
Ar @vairogs/sdk šifrēšana notiek automātiski:
import { VairogsClient } from '@vairogs/sdk'
const client = new VairogsClient({
accessKey: 'vgtk_a_xxx',
decryptionKey: 'vgtk_d_xxx'
})
// Create new password
const newPassword = await client.createItem('PASSWORD', 'GitHub Login', {
username: 'user@example.com',
password: 'secret123',
url: 'https://github.com'
})
// Create note
const newNote = await client.createItem('NOTE', 'Important note', {
content: 'This is secret text...'
})
// Update item
await client.updateItem('item_abc123', {
username: 'newuser@example.com',
password: 'newpassword456'
})
// Delete item
await client.deleteItem('item_abc123')400Bad RequestNepareizi formatēti dati vai trūkst obligāto lauku.
401UnauthorizedNederīga vai trūkstoša API atslēga.
403ForbiddenNav atļaujas veikt šo darbību (piemēram, items:write nav iespējots).
404Not FoundVienums ar norādīto ID neeksistē vai nav pieejams.