web3ql-client 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -0
- package/contracts/PublicKeyRegistry.sol +87 -0
- package/dist/src/access.d.ts +176 -0
- package/dist/src/access.d.ts.map +1 -0
- package/dist/src/access.js +283 -0
- package/dist/src/access.js.map +1 -0
- package/dist/src/batch.d.ts +107 -0
- package/dist/src/batch.d.ts.map +1 -0
- package/dist/src/batch.js +188 -0
- package/dist/src/batch.js.map +1 -0
- package/dist/src/cli.d.ts +40 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +361 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/constraints.d.ts +126 -0
- package/dist/src/constraints.d.ts.map +1 -0
- package/dist/src/constraints.js +192 -0
- package/dist/src/constraints.js.map +1 -0
- package/dist/src/crypto.d.ts +118 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/crypto.js +192 -0
- package/dist/src/crypto.js.map +1 -0
- package/dist/src/factory-client.d.ts +106 -0
- package/dist/src/factory-client.d.ts.map +1 -0
- package/dist/src/factory-client.js +202 -0
- package/dist/src/factory-client.js.map +1 -0
- package/dist/src/index-cache.d.ts +156 -0
- package/dist/src/index-cache.d.ts.map +1 -0
- package/dist/src/index-cache.js +265 -0
- package/dist/src/index-cache.js.map +1 -0
- package/dist/src/index.d.ts +60 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +60 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/migrations.d.ts +114 -0
- package/dist/src/migrations.d.ts.map +1 -0
- package/dist/src/migrations.js +173 -0
- package/dist/src/migrations.js.map +1 -0
- package/dist/src/model.d.ts +198 -0
- package/dist/src/model.d.ts.map +1 -0
- package/dist/src/model.js +379 -0
- package/dist/src/model.js.map +1 -0
- package/dist/src/query.d.ts +155 -0
- package/dist/src/query.d.ts.map +1 -0
- package/dist/src/query.js +386 -0
- package/dist/src/query.js.map +1 -0
- package/dist/src/registry.d.ts +45 -0
- package/dist/src/registry.d.ts.map +1 -0
- package/dist/src/registry.js +80 -0
- package/dist/src/registry.js.map +1 -0
- package/dist/src/schema-manager.d.ts +109 -0
- package/dist/src/schema-manager.d.ts.map +1 -0
- package/dist/src/schema-manager.js +259 -0
- package/dist/src/schema-manager.js.map +1 -0
- package/dist/src/table-client.d.ts +156 -0
- package/dist/src/table-client.d.ts.map +1 -0
- package/dist/src/table-client.js +292 -0
- package/dist/src/table-client.js.map +1 -0
- package/dist/src/typed-table.d.ts +159 -0
- package/dist/src/typed-table.d.ts.map +1 -0
- package/dist/src/typed-table.js +246 -0
- package/dist/src/typed-table.js.map +1 -0
- package/dist/src/types.d.ts +48 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +222 -0
- package/dist/src/types.js.map +1 -0
- package/keyManager.js +337 -0
- package/package.json +38 -0
- package/src/access.ts +421 -0
- package/src/batch.ts +259 -0
- package/src/cli.ts +349 -0
- package/src/constraints.ts +283 -0
- package/src/crypto.ts +239 -0
- package/src/factory-client.ts +237 -0
- package/src/index-cache.ts +351 -0
- package/src/index.ts +171 -0
- package/src/migrations.ts +215 -0
- package/src/model.ts +538 -0
- package/src/query.ts +508 -0
- package/src/registry.ts +100 -0
- package/src/schema-manager.ts +301 -0
- package/src/table-client.ts +393 -0
- package/src/typed-table.ts +340 -0
- package/src/types.ts +284 -0
- package/tsconfig.json +22 -0
- package/walletUtils.js +204 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @web3ql/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript client SDK for the Web3QL on-chain encrypted database system. End-to-end NaCl encryption — plaintext never touches the chain.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @web3ql/sdk ethers tweetnacl @noble/hashes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Web3QLClient, EncryptedTableClient, deriveKeypairFromWallet } from '@web3ql/sdk'
|
|
15
|
+
import { ethers } from 'ethers'
|
|
16
|
+
|
|
17
|
+
const provider = new ethers.JsonRpcProvider('https://forno.celo-sepolia.celo-testnet.org')
|
|
18
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider)
|
|
19
|
+
|
|
20
|
+
// Derive keypair — same result as browser Explorer
|
|
21
|
+
const keypair = await deriveKeypairFromWallet(wallet)
|
|
22
|
+
|
|
23
|
+
const client = new Web3QLClient('0x2cfE616062261927fCcC727333d6dD3D5880FDd1', wallet)
|
|
24
|
+
const db = await client.createDatabase('my_app')
|
|
25
|
+
const table = await db.createTable('users', '{"name":"string"}')
|
|
26
|
+
|
|
27
|
+
const enc = new EncryptedTableClient(table.address, wallet, keypair)
|
|
28
|
+
await enc.writeString('user_001', JSON.stringify({ name: 'Alice' }))
|
|
29
|
+
const plain = await enc.readString('user_001') // decrypts on read
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Key exports
|
|
33
|
+
|
|
34
|
+
| Export | Description |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `Web3QLClient` | Top-level: createDatabase(), getUserDatabases() |
|
|
37
|
+
| `DatabaseClient` | createTable(), getTable(), listTables() |
|
|
38
|
+
| `EncryptedTableClient` | write/read/update/delete + grantAccess() |
|
|
39
|
+
| `TypedTableClient` | Prisma-style: create(), findMany(), updateById() |
|
|
40
|
+
| `PublicKeyRegistryClient` | register(), getPublicKey(), hasKey() |
|
|
41
|
+
| `deriveKeypairFromWallet(signer)` | ✅ Recommended — browser-compatible |
|
|
42
|
+
| `deriveKeypair(privKey)` | ⚠️ Deprecated — different keypair from browser |
|
|
43
|
+
|
|
44
|
+
## Key derivation
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Signs 'Web3QL encryption key derivation v1' deterministically
|
|
48
|
+
// SHA-256(signature) → X25519 seed → NaCl keypair
|
|
49
|
+
// Identical result in browser (MetaMask) and server (ethers Wallet)
|
|
50
|
+
const keypair = await deriveKeypairFromWallet(wallet)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Always use `deriveKeypairFromWallet` so SDK-written records are readable in the Web3QL Cloud Explorer browser UI.
|
|
54
|
+
|
|
55
|
+
## Encryption model
|
|
56
|
+
|
|
57
|
+
- Per-record random 32-byte symmetric key → NaCl secretbox (XSalsa20-Poly1305)
|
|
58
|
+
- Symmetric key wrapped per recipient → NaCl box (X25519 ECDH)
|
|
59
|
+
- `secretbox blob = [ 24-byte nonce | encrypted(plaintext, symKey) ]`
|
|
60
|
+
- `key envelope = [ 24-byte nonce | box(symKey, myPriv, recipientPub) ]`
|
|
61
|
+
|
|
62
|
+
## Build
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd sdk && pnpm install && pnpm build
|
|
66
|
+
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @title PublicKeyRegistry
|
|
6
|
+
* @notice Stores one X25519 encryption public key per Ethereum address.
|
|
7
|
+
*
|
|
8
|
+
* Why is this needed?
|
|
9
|
+
* ─────────────────────────────────────────────────────────────
|
|
10
|
+
* When Alice wants to share a record with Bob, she needs Bob's
|
|
11
|
+
* X25519 public key to encrypt the symmetric key for him.
|
|
12
|
+
* Bob registers his public key here once (~40k gas), and Alice
|
|
13
|
+
* looks it up before calling grantAccess().
|
|
14
|
+
*
|
|
15
|
+
* Key derivation (SDK side):
|
|
16
|
+
* The X25519 private key = SHA-256(Ethereum private key)
|
|
17
|
+
* The X25519 public key = scalar_mult(privKey, Curve25519.G)
|
|
18
|
+
* This is done entirely off-chain in @web3ql/sdk's crypto module.
|
|
19
|
+
*
|
|
20
|
+
* Security:
|
|
21
|
+
* • Registering here reveals only the X25519 PUBLIC key.
|
|
22
|
+
* • The Ethereum private key and X25519 private key are never
|
|
23
|
+
* transmitted or stored anywhere.
|
|
24
|
+
* • Users can rotate their key at any time by calling register()
|
|
25
|
+
* again — old encrypted records won't be accessible with the
|
|
26
|
+
* new key (same as real-world key rotation).
|
|
27
|
+
*
|
|
28
|
+
* @dev Intentionally NOT upgradeable — immutable registry.
|
|
29
|
+
* Deploy once on Celo, share the address in the SDK config.
|
|
30
|
+
*/
|
|
31
|
+
contract PublicKeyRegistry {
|
|
32
|
+
|
|
33
|
+
// ─────────────────────────────────────────────────────────
|
|
34
|
+
// State
|
|
35
|
+
// ─────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/// address → X25519 public key (32 bytes packed into bytes32)
|
|
38
|
+
mapping(address => bytes32) private _keys;
|
|
39
|
+
|
|
40
|
+
// ─────────────────────────────────────────────────────────
|
|
41
|
+
// Events
|
|
42
|
+
// ─────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
event KeyRegistered(address indexed user, bytes32 publicKey);
|
|
45
|
+
|
|
46
|
+
// ─────────────────────────────────────────────────────────
|
|
47
|
+
// Write
|
|
48
|
+
// ─────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @notice Register (or rotate) your X25519 encryption public key.
|
|
52
|
+
* @param pubKey 32-byte X25519 public key from @web3ql/sdk's deriveKeypair().
|
|
53
|
+
*
|
|
54
|
+
* One-time cost ~40k gas on Celo (~$0.001).
|
|
55
|
+
* Can be re-called to rotate the key — existing encrypted records
|
|
56
|
+
* will need to be re-shared by their owners after rotation.
|
|
57
|
+
*/
|
|
58
|
+
function register(bytes32 pubKey) external {
|
|
59
|
+
require(pubKey != bytes32(0), "PublicKeyRegistry: pubKey must not be zero");
|
|
60
|
+
_keys[msg.sender] = pubKey;
|
|
61
|
+
emit KeyRegistered(msg.sender, pubKey);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─────────────────────────────────────────────────────────
|
|
65
|
+
// Read
|
|
66
|
+
// ─────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @notice Return the X25519 public key for a registered address.
|
|
70
|
+
* @dev Reverts if the address has never registered.
|
|
71
|
+
* Use hasKey() to check first if you want a graceful fallback.
|
|
72
|
+
*/
|
|
73
|
+
function getKey(address user) external view returns (bytes32) {
|
|
74
|
+
require(
|
|
75
|
+
_keys[user] != bytes32(0),
|
|
76
|
+
"PublicKeyRegistry: address has not registered a public key"
|
|
77
|
+
);
|
|
78
|
+
return _keys[user];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @notice Check whether an address has a registered key.
|
|
83
|
+
*/
|
|
84
|
+
function hasKey(address user) external view returns (bool) {
|
|
85
|
+
return _keys[user] != bytes32(0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file access.ts
|
|
3
|
+
* @notice Web3QL v1.2 — advanced access control.
|
|
4
|
+
*
|
|
5
|
+
* Extends the base OWNER/EDITOR/VIEWER per-record model with:
|
|
6
|
+
*
|
|
7
|
+
* 1. TIME-LIMITED ACCESS — expiry block stored in a meta record.
|
|
8
|
+
* SDK checks expiry before decode.
|
|
9
|
+
* 2. DELEGATED SIGNING — sign a capability token so a 3rd party
|
|
10
|
+
* can write on your behalf without your wallet.
|
|
11
|
+
* 3. PUBLIC TABLE MODE — unencrypted writes. Anyone can read.
|
|
12
|
+
* Useful for leaderboards, public state.
|
|
13
|
+
* 4. COLUMN-LEVEL ENCRYPTION — different symmetric key per column.
|
|
14
|
+
* Viewers get keys only for their allowed columns.
|
|
15
|
+
*
|
|
16
|
+
* Usage — time-limited share:
|
|
17
|
+
* ─────────────────────────────────────────────────────────────
|
|
18
|
+
* const am = new AccessManager(tableClient, signer, keypair, registry);
|
|
19
|
+
*
|
|
20
|
+
* // Share record key1 with Bob, expires in 100 blocks
|
|
21
|
+
* await am.shareWithExpiry(key1, bobAddress, Role.VIEWER, registry, 100n);
|
|
22
|
+
*
|
|
23
|
+
* // Bob reads record — SDK auto-checks expiry:
|
|
24
|
+
* const data = await am.readIfNotExpired(key1, bobAddress);
|
|
25
|
+
*
|
|
26
|
+
* Usage — delegated signing:
|
|
27
|
+
* ─────────────────────────────────────────────────────────────
|
|
28
|
+
* // Alice signs a capability token for Bob to write to key1 once
|
|
29
|
+
* const token = await am.signCapability({ key: key1, action: 'write', nonce: 1n });
|
|
30
|
+
*
|
|
31
|
+
* // Bob submits it — the relay/contract verifies Alice's signature
|
|
32
|
+
* await am.submitWithCapability(key1, plaintext, token);
|
|
33
|
+
*
|
|
34
|
+
* Usage — public table:
|
|
35
|
+
* ─────────────────────────────────────────────────────────────
|
|
36
|
+
* const pub = new PublicTableClient(tableAddress, signer);
|
|
37
|
+
* await pub.write(key, plaintext); // stored as plaintext
|
|
38
|
+
* const text = await pub.read(key); // no decryption needed
|
|
39
|
+
* ─────────────────────────────────────────────────────────────
|
|
40
|
+
*/
|
|
41
|
+
import { ethers } from 'ethers';
|
|
42
|
+
import type { EncryptedTableClient } from './table-client.js';
|
|
43
|
+
import { Role } from './table-client.js';
|
|
44
|
+
import type { PublicKeyRegistryClient } from './registry.js';
|
|
45
|
+
import type { EncryptionKeypair } from './crypto.js';
|
|
46
|
+
import { encryptKeyForSelf, decryptKeyForSelf } from './crypto.js';
|
|
47
|
+
export { Role };
|
|
48
|
+
export interface TimedGrant {
|
|
49
|
+
grantee: string;
|
|
50
|
+
role: Role;
|
|
51
|
+
expiryBlock: bigint;
|
|
52
|
+
grantedAt: bigint;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Stores a time-limited grant as a JSON meta record on-chain.
|
|
56
|
+
*
|
|
57
|
+
* Key scheme: keccak256(abi.encodePacked("__grant__", recordKey, grantee))
|
|
58
|
+
*/
|
|
59
|
+
export declare function grantMetaKey(client: EncryptedTableClient, recordKey: string, grantee: string): string;
|
|
60
|
+
export interface CapabilityToken {
|
|
61
|
+
/** Signer's address (granter). */
|
|
62
|
+
granter: string;
|
|
63
|
+
/** Address allowed to use this token. */
|
|
64
|
+
grantee: string;
|
|
65
|
+
/** bytes32 record key the token applies to. */
|
|
66
|
+
key: string;
|
|
67
|
+
/** 'write' | 'update' | 'delete' */
|
|
68
|
+
action: 'write' | 'update' | 'delete';
|
|
69
|
+
/** Monotonic nonce to prevent replay. */
|
|
70
|
+
nonce: bigint;
|
|
71
|
+
/** Block number after which token is invalid. 0 = never expires. */
|
|
72
|
+
expiryBlock: bigint;
|
|
73
|
+
/** ECDSA signature (over the above fields). */
|
|
74
|
+
signature: string;
|
|
75
|
+
}
|
|
76
|
+
export declare class AccessManager {
|
|
77
|
+
private client;
|
|
78
|
+
private signer;
|
|
79
|
+
private keypair;
|
|
80
|
+
constructor(client: EncryptedTableClient, signer: ethers.Signer, keypair: EncryptionKeypair);
|
|
81
|
+
/**
|
|
82
|
+
* Share a record with expiry — stores a signed grant meta record on-chain.
|
|
83
|
+
*
|
|
84
|
+
* @param recordKey bytes32 record key to share.
|
|
85
|
+
* @param recipient Address to grant access to.
|
|
86
|
+
* @param role Role.VIEWER or Role.EDITOR.
|
|
87
|
+
* @param registry PublicKeyRegistryClient to look up recipient's pubkey.
|
|
88
|
+
* @param expiryBlocks Number of blocks until the grant expires.
|
|
89
|
+
*/
|
|
90
|
+
shareWithExpiry(recordKey: string, recipient: string, role: Role, registry: PublicKeyRegistryClient, expiryBlocks: bigint): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Check whether a grant is still valid (not past expiry block).
|
|
93
|
+
* Returns the TimedGrant if valid, null if expired or not found.
|
|
94
|
+
*/
|
|
95
|
+
checkGrant(recordKey: string, grantee: string): Promise<TimedGrant | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Revoke an expired or unwanted timed grant.
|
|
98
|
+
*/
|
|
99
|
+
revokeGrant(recordKey: string, grantee: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Sign a capability token that allows `grantee` to perform `action` on `key`.
|
|
102
|
+
*
|
|
103
|
+
* The signature uses EIP-712 typed data. The relay or contract can verify
|
|
104
|
+
* the granter's address from the signature without trusting the grantee.
|
|
105
|
+
*/
|
|
106
|
+
signCapability(params: {
|
|
107
|
+
grantee: string;
|
|
108
|
+
key: string;
|
|
109
|
+
action: 'write' | 'update' | 'delete';
|
|
110
|
+
nonce: bigint;
|
|
111
|
+
expiryBlock: bigint;
|
|
112
|
+
}): Promise<CapabilityToken>;
|
|
113
|
+
/**
|
|
114
|
+
* Verify a capability token was signed by the stated granter and is not expired.
|
|
115
|
+
* Returns the recovered granter address, or throws if invalid.
|
|
116
|
+
*/
|
|
117
|
+
static verifyCapability(token: CapabilityToken, provider: ethers.Provider): Promise<string>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* PublicTableClient wraps a Web3QL table contract in "no-encryption" mode.
|
|
121
|
+
*
|
|
122
|
+
* Data is stored as raw UTF-8 bytes. Anyone who knows the table address can
|
|
123
|
+
* read every record directly on-chain — no symmetric key required.
|
|
124
|
+
*
|
|
125
|
+
* Use cases: leaderboards, public voting tallies, open datasets.
|
|
126
|
+
*
|
|
127
|
+
* ⚠ All data is FULLY PUBLIC. Do not store sensitive information.
|
|
128
|
+
*/
|
|
129
|
+
export declare class PublicTableClient {
|
|
130
|
+
readonly tableAddress: string;
|
|
131
|
+
private contract;
|
|
132
|
+
private signer;
|
|
133
|
+
constructor(tableAddress: string, signer: ethers.Signer);
|
|
134
|
+
private get c();
|
|
135
|
+
deriveKey(tableName: string, id: bigint): string;
|
|
136
|
+
write(key: string, plaintext: string): Promise<ethers.TransactionReceipt>;
|
|
137
|
+
read(key: string): Promise<string>;
|
|
138
|
+
update(key: string, plaintext: string): Promise<ethers.TransactionReceipt>;
|
|
139
|
+
delete(key: string): Promise<ethers.TransactionReceipt>;
|
|
140
|
+
exists(key: string): Promise<boolean>;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* ColumnKeySet: encrypt specific columns with different symmetric keys.
|
|
144
|
+
*
|
|
145
|
+
* Scenario: a "users" table has columns [id, name, email, salary].
|
|
146
|
+
* You want VIEWER-role collaborators to see name but NOT salary.
|
|
147
|
+
*
|
|
148
|
+
* Solution:
|
|
149
|
+
* • Split row into two groups: visible={id, name} and private={email, salary}
|
|
150
|
+
* • Encrypt each group with a separate symmetric key
|
|
151
|
+
* • VIEWER gets the key for the visible group only
|
|
152
|
+
* • EDITOR gets both keys
|
|
153
|
+
*/
|
|
154
|
+
export interface ColumnKeySet {
|
|
155
|
+
/** Symmetric key for the "public within this sharing scope" columns */
|
|
156
|
+
visibleKey: Uint8Array;
|
|
157
|
+
/** Symmetric key for the private columns */
|
|
158
|
+
privateKey: Uint8Array;
|
|
159
|
+
/** Columns encrypted with visibleKey */
|
|
160
|
+
visibleCols: string[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Split a plain JS row object into two encrypted blobs —
|
|
164
|
+
* one for visible columns, one for private columns.
|
|
165
|
+
*/
|
|
166
|
+
export declare function encryptWithColumnKeys(row: Record<string, unknown>, visibleCols: string[], visibleKey: Uint8Array, privateKey: Uint8Array): {
|
|
167
|
+
visible: Uint8Array;
|
|
168
|
+
private: Uint8Array;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Decrypt and merge the two column blobs.
|
|
172
|
+
*/
|
|
173
|
+
export declare function decryptColumnBlobs(visibleBlob: Uint8Array, privateBlob: Uint8Array, visibleKey: Uint8Array, privateKey: Uint8Array): Record<string, unknown>;
|
|
174
|
+
export declare function generateColumnKeySet(visibleCols: string[]): ColumnKeySet;
|
|
175
|
+
export { encryptKeyForSelf, decryptKeyForSelf };
|
|
176
|
+
//# sourceMappingURL=access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/access.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file access.ts
|
|
3
|
+
* @notice Web3QL v1.2 — advanced access control.
|
|
4
|
+
*
|
|
5
|
+
* Extends the base OWNER/EDITOR/VIEWER per-record model with:
|
|
6
|
+
*
|
|
7
|
+
* 1. TIME-LIMITED ACCESS — expiry block stored in a meta record.
|
|
8
|
+
* SDK checks expiry before decode.
|
|
9
|
+
* 2. DELEGATED SIGNING — sign a capability token so a 3rd party
|
|
10
|
+
* can write on your behalf without your wallet.
|
|
11
|
+
* 3. PUBLIC TABLE MODE — unencrypted writes. Anyone can read.
|
|
12
|
+
* Useful for leaderboards, public state.
|
|
13
|
+
* 4. COLUMN-LEVEL ENCRYPTION — different symmetric key per column.
|
|
14
|
+
* Viewers get keys only for their allowed columns.
|
|
15
|
+
*
|
|
16
|
+
* Usage — time-limited share:
|
|
17
|
+
* ─────────────────────────────────────────────────────────────
|
|
18
|
+
* const am = new AccessManager(tableClient, signer, keypair, registry);
|
|
19
|
+
*
|
|
20
|
+
* // Share record key1 with Bob, expires in 100 blocks
|
|
21
|
+
* await am.shareWithExpiry(key1, bobAddress, Role.VIEWER, registry, 100n);
|
|
22
|
+
*
|
|
23
|
+
* // Bob reads record — SDK auto-checks expiry:
|
|
24
|
+
* const data = await am.readIfNotExpired(key1, bobAddress);
|
|
25
|
+
*
|
|
26
|
+
* Usage — delegated signing:
|
|
27
|
+
* ─────────────────────────────────────────────────────────────
|
|
28
|
+
* // Alice signs a capability token for Bob to write to key1 once
|
|
29
|
+
* const token = await am.signCapability({ key: key1, action: 'write', nonce: 1n });
|
|
30
|
+
*
|
|
31
|
+
* // Bob submits it — the relay/contract verifies Alice's signature
|
|
32
|
+
* await am.submitWithCapability(key1, plaintext, token);
|
|
33
|
+
*
|
|
34
|
+
* Usage — public table:
|
|
35
|
+
* ─────────────────────────────────────────────────────────────
|
|
36
|
+
* const pub = new PublicTableClient(tableAddress, signer);
|
|
37
|
+
* await pub.write(key, plaintext); // stored as plaintext
|
|
38
|
+
* const text = await pub.read(key); // no decryption needed
|
|
39
|
+
* ─────────────────────────────────────────────────────────────
|
|
40
|
+
*/
|
|
41
|
+
import { ethers } from 'ethers';
|
|
42
|
+
import { Role } from './table-client.js';
|
|
43
|
+
import { generateSymmetricKey, encryptData, decryptData, encryptKeyForSelf, decryptKeyForSelf, } from './crypto.js';
|
|
44
|
+
export { Role };
|
|
45
|
+
/**
|
|
46
|
+
* Stores a time-limited grant as a JSON meta record on-chain.
|
|
47
|
+
*
|
|
48
|
+
* Key scheme: keccak256(abi.encodePacked("__grant__", recordKey, grantee))
|
|
49
|
+
*/
|
|
50
|
+
export function grantMetaKey(client, recordKey, grantee) {
|
|
51
|
+
return ethers.keccak256(ethers.solidityPacked(['string', 'bytes32', 'address'], ['__grant__', recordKey, grantee]));
|
|
52
|
+
}
|
|
53
|
+
const CAP_DOMAIN = {
|
|
54
|
+
name: 'Web3QL Capability',
|
|
55
|
+
version: '1',
|
|
56
|
+
};
|
|
57
|
+
const CAP_TYPES = {
|
|
58
|
+
Capability: [
|
|
59
|
+
{ name: 'granter', type: 'address' },
|
|
60
|
+
{ name: 'grantee', type: 'address' },
|
|
61
|
+
{ name: 'key', type: 'bytes32' },
|
|
62
|
+
{ name: 'action', type: 'string' },
|
|
63
|
+
{ name: 'nonce', type: 'uint256' },
|
|
64
|
+
{ name: 'expiryBlock', type: 'uint256' },
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
// ─────────────────────────────────────────────────────────────
|
|
68
|
+
// AccessManager
|
|
69
|
+
// ─────────────────────────────────────────────────────────────
|
|
70
|
+
export class AccessManager {
|
|
71
|
+
client;
|
|
72
|
+
signer;
|
|
73
|
+
keypair;
|
|
74
|
+
constructor(client, signer, keypair) {
|
|
75
|
+
this.client = client;
|
|
76
|
+
this.signer = signer;
|
|
77
|
+
this.keypair = keypair;
|
|
78
|
+
}
|
|
79
|
+
// ── Time-limited sharing ─────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Share a record with expiry — stores a signed grant meta record on-chain.
|
|
82
|
+
*
|
|
83
|
+
* @param recordKey bytes32 record key to share.
|
|
84
|
+
* @param recipient Address to grant access to.
|
|
85
|
+
* @param role Role.VIEWER or Role.EDITOR.
|
|
86
|
+
* @param registry PublicKeyRegistryClient to look up recipient's pubkey.
|
|
87
|
+
* @param expiryBlocks Number of blocks until the grant expires.
|
|
88
|
+
*/
|
|
89
|
+
async shareWithExpiry(recordKey, recipient, role, registry, expiryBlocks) {
|
|
90
|
+
// 1. Standard key share
|
|
91
|
+
await this.client.share(recordKey, recipient, role, registry);
|
|
92
|
+
// 2. Store grant metadata on-chain
|
|
93
|
+
const provider = this.signer.provider;
|
|
94
|
+
const currentBlock = provider ? BigInt(await provider.getBlockNumber()) : 0n;
|
|
95
|
+
const meta = {
|
|
96
|
+
grantee: recipient.toLowerCase(),
|
|
97
|
+
role,
|
|
98
|
+
expiryBlock: currentBlock + expiryBlocks,
|
|
99
|
+
grantedAt: currentBlock,
|
|
100
|
+
};
|
|
101
|
+
const metaKey = grantMetaKey(this.client, recordKey, recipient);
|
|
102
|
+
await this.client.writeRaw(metaKey, JSON.stringify(meta));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check whether a grant is still valid (not past expiry block).
|
|
106
|
+
* Returns the TimedGrant if valid, null if expired or not found.
|
|
107
|
+
*/
|
|
108
|
+
async checkGrant(recordKey, grantee) {
|
|
109
|
+
const metaKey = grantMetaKey(this.client, recordKey, grantee);
|
|
110
|
+
try {
|
|
111
|
+
const exists = await this.client.exists(metaKey);
|
|
112
|
+
if (!exists)
|
|
113
|
+
return null;
|
|
114
|
+
const json = await this.client.readPlaintext(metaKey);
|
|
115
|
+
const grant = JSON.parse(json);
|
|
116
|
+
grant.expiryBlock = BigInt(grant.expiryBlock);
|
|
117
|
+
grant.grantedAt = BigInt(grant.grantedAt);
|
|
118
|
+
const provider = this.signer.provider;
|
|
119
|
+
if (provider) {
|
|
120
|
+
const currentBlock = BigInt(await provider.getBlockNumber());
|
|
121
|
+
if (grant.expiryBlock > 0n && currentBlock > grant.expiryBlock) {
|
|
122
|
+
// Grant has expired — auto-revoke
|
|
123
|
+
await this.client.revoke(recordKey, grantee).catch(() => { });
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return grant;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Revoke an expired or unwanted timed grant.
|
|
135
|
+
*/
|
|
136
|
+
async revokeGrant(recordKey, grantee) {
|
|
137
|
+
await this.client.revoke(recordKey, grantee);
|
|
138
|
+
}
|
|
139
|
+
// ── Capability tokens ────────────────────────────────────────
|
|
140
|
+
/**
|
|
141
|
+
* Sign a capability token that allows `grantee` to perform `action` on `key`.
|
|
142
|
+
*
|
|
143
|
+
* The signature uses EIP-712 typed data. The relay or contract can verify
|
|
144
|
+
* the granter's address from the signature without trusting the grantee.
|
|
145
|
+
*/
|
|
146
|
+
async signCapability(params) {
|
|
147
|
+
const granter = await this.signer.getAddress();
|
|
148
|
+
const message = {
|
|
149
|
+
granter,
|
|
150
|
+
grantee: params.grantee,
|
|
151
|
+
key: params.key,
|
|
152
|
+
action: params.action,
|
|
153
|
+
nonce: params.nonce,
|
|
154
|
+
expiryBlock: params.expiryBlock,
|
|
155
|
+
};
|
|
156
|
+
const signature = await this.signer.signTypedData(CAP_DOMAIN, CAP_TYPES, message);
|
|
157
|
+
return { ...message, signature, granter };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Verify a capability token was signed by the stated granter and is not expired.
|
|
161
|
+
* Returns the recovered granter address, or throws if invalid.
|
|
162
|
+
*/
|
|
163
|
+
static async verifyCapability(token, provider) {
|
|
164
|
+
const currentBlock = BigInt(await provider.getBlockNumber());
|
|
165
|
+
if (token.expiryBlock > 0n && currentBlock > token.expiryBlock) {
|
|
166
|
+
throw new Error('CapabilityToken: expired');
|
|
167
|
+
}
|
|
168
|
+
const message = {
|
|
169
|
+
granter: token.granter,
|
|
170
|
+
grantee: token.grantee,
|
|
171
|
+
key: token.key,
|
|
172
|
+
action: token.action,
|
|
173
|
+
nonce: token.nonce,
|
|
174
|
+
expiryBlock: token.expiryBlock,
|
|
175
|
+
};
|
|
176
|
+
const recovered = ethers.verifyTypedData(CAP_DOMAIN, CAP_TYPES, message, token.signature);
|
|
177
|
+
if (recovered.toLowerCase() !== token.granter.toLowerCase()) {
|
|
178
|
+
throw new Error('CapabilityToken: signature mismatch');
|
|
179
|
+
}
|
|
180
|
+
return recovered;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ─────────────────────────────────────────────────────────────
|
|
184
|
+
// Public table mode (no encryption)
|
|
185
|
+
// ─────────────────────────────────────────────────────────────
|
|
186
|
+
const PUBLIC_TABLE_ABI = [
|
|
187
|
+
'function write(bytes32 key, bytes calldata ciphertext, bytes calldata encryptedKey) external',
|
|
188
|
+
'function read(bytes32 key) external view returns (bytes memory ciphertext, bool deleted, uint256 version, uint256 updatedAt, address owner)',
|
|
189
|
+
'function update(bytes32 key, bytes calldata ciphertext, bytes calldata encryptedKey) external',
|
|
190
|
+
'function deleteRecord(bytes32 key) external',
|
|
191
|
+
'function recordExists(bytes32 key) external view returns (bool)',
|
|
192
|
+
];
|
|
193
|
+
/**
|
|
194
|
+
* PublicTableClient wraps a Web3QL table contract in "no-encryption" mode.
|
|
195
|
+
*
|
|
196
|
+
* Data is stored as raw UTF-8 bytes. Anyone who knows the table address can
|
|
197
|
+
* read every record directly on-chain — no symmetric key required.
|
|
198
|
+
*
|
|
199
|
+
* Use cases: leaderboards, public voting tallies, open datasets.
|
|
200
|
+
*
|
|
201
|
+
* ⚠ All data is FULLY PUBLIC. Do not store sensitive information.
|
|
202
|
+
*/
|
|
203
|
+
export class PublicTableClient {
|
|
204
|
+
tableAddress;
|
|
205
|
+
contract;
|
|
206
|
+
signer;
|
|
207
|
+
constructor(tableAddress, signer) {
|
|
208
|
+
this.tableAddress = tableAddress;
|
|
209
|
+
this.signer = signer;
|
|
210
|
+
this.contract = new ethers.Contract(tableAddress, PUBLIC_TABLE_ABI, signer);
|
|
211
|
+
}
|
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
213
|
+
get c() { return this.contract; }
|
|
214
|
+
deriveKey(tableName, id) {
|
|
215
|
+
return ethers.solidityPackedKeccak256(['string', 'uint256'], [tableName, id]);
|
|
216
|
+
}
|
|
217
|
+
async write(key, plaintext) {
|
|
218
|
+
const data = new TextEncoder().encode(plaintext);
|
|
219
|
+
// Contract requires encryptedKey.length > 0 — use 1-byte public marker
|
|
220
|
+
const publicMarker = new Uint8Array([0x50]); // 'P' for Public
|
|
221
|
+
const tx = await this.c.write(key, data, publicMarker);
|
|
222
|
+
return tx.wait();
|
|
223
|
+
}
|
|
224
|
+
async read(key) {
|
|
225
|
+
const [ciphertext /* rest ignored */] = await this.c.read(key);
|
|
226
|
+
return new TextDecoder().decode(ethers.getBytes(ciphertext));
|
|
227
|
+
}
|
|
228
|
+
async update(key, plaintext) {
|
|
229
|
+
const data = new TextEncoder().encode(plaintext);
|
|
230
|
+
const publicMarker = new Uint8Array([0x50]);
|
|
231
|
+
const tx = await this.c.update(key, data, publicMarker);
|
|
232
|
+
return tx.wait();
|
|
233
|
+
}
|
|
234
|
+
async delete(key) {
|
|
235
|
+
const tx = await this.c.deleteRecord(key);
|
|
236
|
+
return tx.wait();
|
|
237
|
+
}
|
|
238
|
+
async exists(key) {
|
|
239
|
+
return this.c.recordExists(key);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Split a plain JS row object into two encrypted blobs —
|
|
244
|
+
* one for visible columns, one for private columns.
|
|
245
|
+
*/
|
|
246
|
+
export function encryptWithColumnKeys(row, visibleCols, visibleKey, privateKey) {
|
|
247
|
+
const visiblePart = {};
|
|
248
|
+
const privatePart = {};
|
|
249
|
+
for (const [k, v] of Object.entries(row)) {
|
|
250
|
+
if (visibleCols.includes(k))
|
|
251
|
+
visiblePart[k] = v;
|
|
252
|
+
else
|
|
253
|
+
privatePart[k] = v;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
visible: encryptData(new TextEncoder().encode(JSON.stringify(visiblePart)), visibleKey),
|
|
257
|
+
private: encryptData(new TextEncoder().encode(JSON.stringify(privatePart)), privateKey),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Decrypt and merge the two column blobs.
|
|
262
|
+
*/
|
|
263
|
+
export function decryptColumnBlobs(visibleBlob, privateBlob, visibleKey, privateKey) {
|
|
264
|
+
const visibleText = new TextDecoder().decode(decryptData(visibleBlob, visibleKey));
|
|
265
|
+
const privateText = new TextDecoder().decode(decryptData(privateBlob, privateKey));
|
|
266
|
+
return {
|
|
267
|
+
...JSON.parse(visibleText),
|
|
268
|
+
...JSON.parse(privateText),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// ─────────────────────────────────────────────────────────────
|
|
272
|
+
// Convenience: generate fresh column key set
|
|
273
|
+
// ─────────────────────────────────────────────────────────────
|
|
274
|
+
export function generateColumnKeySet(visibleCols) {
|
|
275
|
+
return {
|
|
276
|
+
visibleKey: generateSymmetricKey(),
|
|
277
|
+
privateKey: generateSymmetricKey(),
|
|
278
|
+
visibleCols,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
// Export for self-encryption helpers (used by AccessManager internally)
|
|
282
|
+
export { encryptKeyForSelf, decryptKeyForSelf };
|
|
283
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../src/access.ts"],"names":[],"mappings":"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"}
|