feat(server): 新增云端缓存与同步服务端骨架
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
96
server/src/routes/vault.js
Normal file
96
server/src/routes/vault.js
Normal file
@@ -0,0 +1,96 @@
|
||||
const db = require('../db');
|
||||
const { requireAuth } = require('../auth');
|
||||
|
||||
function normalizeVaultItem(item) {
|
||||
if (!item || typeof item !== 'object') {
|
||||
return null;
|
||||
}
|
||||
var itemType = String(item.itemType || '').trim().slice(0, 64);
|
||||
var itemKey = String(item.itemKey || '').trim().slice(0, 191);
|
||||
var payloadCiphertext = String(item.payloadCiphertext || '').trim();
|
||||
var payloadIv = String(item.payloadIv || '').trim().slice(0, 128);
|
||||
var payloadTag = String(item.payloadTag || '').trim().slice(0, 128);
|
||||
var payloadHash = String(item.payloadHash || '').trim().slice(0, 64);
|
||||
var keyVersion = Math.max(1, Number(item.keyVersion) || 1);
|
||||
|
||||
if (!itemType || !itemKey || !payloadCiphertext || !payloadIv || !payloadTag || !payloadHash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
itemType: itemType,
|
||||
itemKey: itemKey,
|
||||
payloadCiphertext: payloadCiphertext,
|
||||
payloadIv: payloadIv,
|
||||
payloadTag: payloadTag,
|
||||
payloadHash: payloadHash,
|
||||
keyVersion: keyVersion
|
||||
};
|
||||
}
|
||||
|
||||
async function routes(fastify) {
|
||||
fastify.addHook('preHandler', requireAuth);
|
||||
|
||||
fastify.post('/api/vault/push', async function (request, reply) {
|
||||
var items = Array.isArray(request.body && request.body.items) ? request.body.items : [];
|
||||
var normalized = items.map(normalizeVaultItem).filter(Boolean);
|
||||
var index = 0;
|
||||
var item = null;
|
||||
if (normalized.length === 0) {
|
||||
reply.code(400);
|
||||
return { ok: false, error: '没有可保存的保险柜项目' };
|
||||
}
|
||||
|
||||
for (index = 0; index < normalized.length; index++) {
|
||||
item = normalized[index];
|
||||
await db.execute(
|
||||
'INSERT INTO vault_items (user_id, item_type, item_key, payload_ciphertext, payload_iv, payload_tag, payload_hash, key_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE payload_ciphertext = VALUES(payload_ciphertext), payload_iv = VALUES(payload_iv), payload_tag = VALUES(payload_tag), payload_hash = VALUES(payload_hash), key_version = VALUES(key_version), updated_at = CURRENT_TIMESTAMP',
|
||||
[
|
||||
request.authContext.user.id,
|
||||
item.itemType,
|
||||
item.itemKey,
|
||||
item.payloadCiphertext,
|
||||
item.payloadIv,
|
||||
item.payloadTag,
|
||||
item.payloadHash,
|
||||
item.keyVersion
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return { ok: true, savedCount: normalized.length };
|
||||
});
|
||||
|
||||
fastify.post('/api/vault/pull', async function (request) {
|
||||
var itemTypes = Array.isArray(request.body && request.body.itemTypes) ? request.body.itemTypes.map(function (itemType) {
|
||||
return String(itemType || '').trim().slice(0, 64);
|
||||
}).filter(Boolean) : [];
|
||||
|
||||
var sql = 'SELECT item_type, item_key, payload_ciphertext, payload_iv, payload_tag, payload_hash, key_version, updated_at FROM vault_items WHERE user_id = ?';
|
||||
var params = [request.authContext.user.id];
|
||||
if (itemTypes.length > 0) {
|
||||
sql += ' AND item_type IN (' + itemTypes.map(function () { return '?'; }).join(',') + ')';
|
||||
params = params.concat(itemTypes);
|
||||
}
|
||||
sql += ' ORDER BY updated_at DESC';
|
||||
|
||||
var rows = await db.query(sql, params);
|
||||
return {
|
||||
ok: true,
|
||||
items: rows.map(function (row) {
|
||||
return {
|
||||
itemType: row.item_type,
|
||||
itemKey: row.item_key,
|
||||
payloadCiphertext: row.payload_ciphertext,
|
||||
payloadIv: row.payload_iv,
|
||||
payloadTag: row.payload_tag,
|
||||
payloadHash: row.payload_hash,
|
||||
keyVersion: Number(row.key_version || 1),
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
Reference in New Issue
Block a user