Skip to content

Commit ca89709

Browse files
author
teycir
committed
feat: add blob hash, unlock message, expiration, and access count to seals
- Extend SealRecord and database schema with optional blobHash, unlockMessage, expiresAt, and accessCount fields - Update createSeal and getSeal operations to handle new fields, including access count increment on retrieval - Enhance SealService interfaces to support unlock message and expiration days in creation requests - Improve seal metadata to include new fields for better tracking and user experience
1 parent 839e572 commit ca89709

3 files changed

Lines changed: 43 additions & 4 deletions

File tree

lib/database.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export interface SealRecord {
2222
iv: string;
2323
pulseToken?: string;
2424
createdAt: number;
25+
blobHash?: string;
26+
unlockMessage?: string;
27+
expiresAt?: number;
28+
accessCount?: number;
2529
}
2630

2731
// Production D1 Database
@@ -39,13 +43,17 @@ export class SealDatabase implements DatabaseProvider {
3943
iv: String(result.iv || ''),
4044
pulseToken: result.pulse_token ? String(result.pulse_token) : undefined,
4145
createdAt: Number(result.created_at || 0),
46+
blobHash: result.blob_hash ? String(result.blob_hash) : undefined,
47+
unlockMessage: result.unlock_message ? String(result.unlock_message) : undefined,
48+
expiresAt: result.expires_at ? Number(result.expires_at) : undefined,
49+
accessCount: result.access_count ? Number(result.access_count) : 0,
4250
};
4351
}
4452

4553
async createSeal(data: SealRecord): Promise<void> {
4654
const result = await this.db.prepare(
47-
`INSERT INTO seals (id, unlock_time, is_dms, pulse_interval, last_pulse, key_b, iv, pulse_token, created_at)
48-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
55+
`INSERT INTO seals (id, unlock_time, is_dms, pulse_interval, last_pulse, key_b, iv, pulse_token, created_at, blob_hash, unlock_message, expires_at, access_count)
56+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
4957
).bind(
5058
data.id,
5159
data.unlockTime,
@@ -55,7 +63,11 @@ export class SealDatabase implements DatabaseProvider {
5563
data.keyB,
5664
data.iv,
5765
data.pulseToken || null,
58-
data.createdAt
66+
data.createdAt,
67+
data.blobHash || null,
68+
data.unlockMessage || null,
69+
data.expiresAt || null,
70+
data.accessCount || 0
5971
).run();
6072

6173
if (!result.success) {
@@ -69,6 +81,12 @@ export class SealDatabase implements DatabaseProvider {
6981
).bind(id).first();
7082

7183
if (!result) return null;
84+
85+
// Increment access count
86+
await this.db.prepare(
87+
'UPDATE seals SET access_count = access_count + 1 WHERE id = ?'
88+
).bind(id).run();
89+
7290
return this.mapResultToSealRecord(result);
7391
}
7492

lib/sealService.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export interface CreateSealRequest {
1616
unlockTime: number;
1717
isDMS?: boolean;
1818
pulseInterval?: number;
19+
unlockMessage?: string;
20+
expiresAfterDays?: number;
1921
}
2022

2123
export interface SealMetadata {
@@ -25,6 +27,9 @@ export interface SealMetadata {
2527
status: 'locked' | 'unlocked';
2628
keyB?: string;
2729
iv?: string;
30+
blobHash?: string;
31+
unlockMessage?: string;
32+
accessCount?: number;
2833
}
2934

3035
export interface SealReceipt {
@@ -76,6 +81,11 @@ export class SealService {
7681
// Generate cryptographic receipt
7782
const blobHash = await this.hashBlob(request.encryptedBlob);
7883
const receipt = await this.generateReceipt(sealId, blobHash, request.unlockTime, createdAt);
84+
85+
// Calculate expiration
86+
const expiresAt = request.expiresAfterDays
87+
? request.unlockTime + (request.expiresAfterDays * 24 * 60 * 60 * 1000)
88+
: undefined;
7989

8090
// Create seal record first
8191
await this.db.createSeal({
@@ -88,6 +98,10 @@ export class SealService {
8898
iv: request.iv,
8999
pulseToken,
90100
createdAt,
101+
blobHash,
102+
unlockMessage: request.unlockMessage,
103+
expiresAt,
104+
accessCount: 0,
91105
});
92106

93107
// Then upload blob (D1BlobStorage needs the row to exist)
@@ -141,6 +155,9 @@ export class SealService {
141155
status: isUnlocked ? 'unlocked' : 'locked',
142156
keyB: decryptedKeyB,
143157
iv: isUnlocked ? seal.iv : undefined,
158+
blobHash: seal.blobHash,
159+
unlockMessage: isUnlocked ? seal.unlockMessage : undefined,
160+
accessCount: seal.accessCount,
144161
};
145162
}
146163

schema.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ CREATE TABLE IF NOT EXISTS seals (
99
iv TEXT NOT NULL,
1010
encrypted_blob TEXT,
1111
pulse_token TEXT,
12-
created_at INTEGER NOT NULL
12+
created_at INTEGER NOT NULL,
13+
blob_hash TEXT,
14+
unlock_message TEXT,
15+
expires_at INTEGER,
16+
access_count INTEGER DEFAULT 0
1317
);
1418

1519
CREATE INDEX IF NOT EXISTS idx_seals_unlock_time ON seals(unlock_time);

0 commit comments

Comments
 (0)