@neus/sdk 1.0.0 → 1.0.1
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/LICENSE +36 -40
- package/README.md +86 -152
- package/SECURITY.md +29 -224
- package/cjs/client.cjs +1686 -0
- package/cjs/errors.cjs +202 -0
- package/cjs/gates.cjs +140 -0
- package/cjs/index.cjs +2315 -0
- package/cjs/utils.cjs +620 -0
- package/client.js +1693 -844
- package/errors.js +223 -228
- package/gates.js +175 -0
- package/index.js +21 -26
- package/package.json +68 -18
- package/types.d.ts +519 -71
- package/utils.js +752 -722
- package/widgets/README.md +53 -0
- package/widgets/index.js +9 -0
- package/widgets/verify-gate/dist/ProofBadge.js +355 -0
- package/widgets/verify-gate/dist/VerifyGate.js +601 -0
- package/widgets/verify-gate/index.js +13 -0
- package/widgets.cjs +20 -0
package/LICENSE
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
10
|
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
11
|
|
|
12
|
-
"Licensor" shall mean the copyright owner or entity
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
13
14
|
|
|
14
15
|
"Legal Entity" shall mean the union of the acting entity and all
|
|
15
16
|
other entities that control, are controlled by, or are under common
|
|
@@ -34,13 +35,15 @@
|
|
|
34
35
|
"Work" shall mean the work of authorship, whether in Source or
|
|
35
36
|
Object form, made available under the License, as indicated by a
|
|
36
37
|
copyright notice that is included in or attached to the work
|
|
37
|
-
(
|
|
38
|
-
marked or otherwise designated in writing by the copyright owner
|
|
39
|
-
as "Not a Contribution").
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
40
39
|
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
44
47
|
|
|
45
48
|
"Contribution" shall mean any work of authorship, including
|
|
46
49
|
the original version of the Work and any modifications or additions
|
|
@@ -50,16 +53,20 @@
|
|
|
50
53
|
the copyright owner. For the purposes of this definition, "submitted"
|
|
51
54
|
means any form of electronic, verbal, or written communication sent
|
|
52
55
|
to the Licensor or its representatives, including but not limited to
|
|
53
|
-
communication on electronic mailing lists, source code control
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
designated in writing by the copyright owner as "Not a Contribution"
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
58
65
|
|
|
59
66
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
60
67
|
this License, each Contributor hereby grants to You a perpetual,
|
|
61
68
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
62
|
-
copyright license to
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
63
70
|
publicly display, publicly perform, sublicense, and distribute the
|
|
64
71
|
Work and such Derivative Works in Source or Object form.
|
|
65
72
|
|
|
@@ -113,11 +120,12 @@
|
|
|
113
120
|
that such additional attribution notices cannot be construed
|
|
114
121
|
as modifying the License.
|
|
115
122
|
|
|
116
|
-
You may add Your own copyright
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
121
129
|
|
|
122
130
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
123
131
|
any Contribution intentionally submitted for inclusion in the Work
|
|
@@ -154,28 +162,16 @@
|
|
|
154
162
|
other commercial damages or losses), even if such Contributor
|
|
155
163
|
has been advised of the possibility of such damages.
|
|
156
164
|
|
|
157
|
-
9. Accepting Warranty or
|
|
158
|
-
Derivative Works thereof, You may choose to offer,
|
|
159
|
-
for, acceptance of support, warranty, indemnity,
|
|
160
|
-
obligations and/or rights consistent with this
|
|
161
|
-
accepting such obligations, You may act only
|
|
162
|
-
on Your sole responsibility, not on behalf
|
|
163
|
-
and only if You agree to indemnify,
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
166
175
|
|
|
167
176
|
END OF TERMS AND CONDITIONS
|
|
168
177
|
|
|
169
|
-
Copyright 2025 NEUS Network, Inc.
|
|
170
|
-
|
|
171
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
172
|
-
you may not use this file except in compliance with the License.
|
|
173
|
-
You may obtain a copy of the License at
|
|
174
|
-
|
|
175
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
176
|
-
|
|
177
|
-
Unless required by applicable law or agreed to in writing, software
|
|
178
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
179
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
180
|
-
See the License for the specific language governing permissions and
|
|
181
|
-
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,206 +1,140 @@
|
|
|
1
1
|
# NEUS SDK
|
|
2
2
|
|
|
3
|
-
JavaScript client for NEUS Network
|
|
3
|
+
JavaScript client (and optional widgets) for the NEUS Network verification API.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @neus/sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Create a proof (browser wallet flow)
|
|
12
|
+
|
|
13
|
+
This path requests a wallet signature in the browser and submits the verification request:
|
|
12
14
|
|
|
13
15
|
```javascript
|
|
14
16
|
import { NeusClient } from '@neus/sdk';
|
|
15
17
|
|
|
16
|
-
const client = new NeusClient();
|
|
17
|
-
const proof = await client.verify({
|
|
18
|
-
verifier: 'ownership-basic',
|
|
19
|
-
content: 'Hello NEUS Network'
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
console.log('Proof created:', proof.qHash);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Basic Usage
|
|
26
|
-
|
|
27
|
-
### Create Proof
|
|
18
|
+
const client = new NeusClient({ apiUrl: 'https://api.neus.network' });
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
// Content ownership
|
|
31
|
-
const proof = await client.verify({
|
|
20
|
+
const res = await client.verify({
|
|
32
21
|
verifier: 'ownership-basic',
|
|
33
|
-
content: '
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// NFT ownership
|
|
37
|
-
const proof = await client.verify({
|
|
38
|
-
verifier: 'nft-ownership',
|
|
39
|
-
data: {
|
|
40
|
-
ownerAddress: walletAddress,
|
|
41
|
-
contractAddress: '0x...',
|
|
42
|
-
tokenId: '1234',
|
|
43
|
-
chainId: 1
|
|
44
|
-
}
|
|
22
|
+
content: 'Hello NEUS',
|
|
23
|
+
wallet: window.ethereum
|
|
45
24
|
});
|
|
46
25
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
data: {
|
|
51
|
-
ownerAddress: walletAddress,
|
|
52
|
-
contractAddress: '0x...',
|
|
53
|
-
minBalance: '100.0',
|
|
54
|
-
chainId: 1
|
|
55
|
-
}
|
|
56
|
-
});
|
|
26
|
+
// Proof ID (qHash): stable identifier you can store and use for status polling
|
|
27
|
+
const proofId = res.qHash;
|
|
28
|
+
const status = await client.getStatus(proofId);
|
|
57
29
|
```
|
|
58
30
|
|
|
59
|
-
|
|
31
|
+
## Client configuration
|
|
60
32
|
|
|
61
33
|
```javascript
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
### Monitor Progress
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
// Poll until completion
|
|
74
|
-
const finalStatus = await client.pollProofStatus(proof.qHash, {
|
|
75
|
-
interval: 3000,
|
|
76
|
-
onProgress: (status) => console.log('Current status:', status.status)
|
|
34
|
+
const client = new NeusClient({
|
|
35
|
+
// Optional: point at a self-hosted deployment
|
|
36
|
+
apiUrl: 'https://api.neus.network',
|
|
37
|
+
// Optional: request timeout (ms)
|
|
38
|
+
timeout: 30000,
|
|
39
|
+
// Optional: server-side enterprise API key for higher limits on eligible endpoints
|
|
40
|
+
// (Do not embed API keys in browser apps.)
|
|
41
|
+
apiKey: process.env.NEUS_API_KEY
|
|
77
42
|
});
|
|
78
43
|
```
|
|
79
44
|
|
|
80
|
-
##
|
|
45
|
+
## Create a proof (server / manual signing)
|
|
46
|
+
|
|
47
|
+
If you already have a signature over the NEUS Standard Signing String, submit it directly:
|
|
81
48
|
|
|
82
49
|
```javascript
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
50
|
+
const res = await client.verify({
|
|
51
|
+
verifierIds: ['ownership-basic'],
|
|
52
|
+
data: {
|
|
53
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
54
|
+
content: 'Hello NEUS',
|
|
55
|
+
reference: { type: 'url', id: 'https://example.com' }
|
|
56
|
+
},
|
|
57
|
+
walletAddress: '0x1111111111111111111111111111111111111111',
|
|
58
|
+
signature: '0x...',
|
|
59
|
+
signedTimestamp: Date.now(),
|
|
60
|
+
chainId: 84532,
|
|
61
|
+
options: { privacyLevel: 'private' }
|
|
86
62
|
});
|
|
87
63
|
```
|
|
88
64
|
|
|
89
|
-
##
|
|
65
|
+
## What verifiers are available?
|
|
90
66
|
|
|
91
|
-
|
|
92
|
-
// Public proof - publicly accessible verification details
|
|
93
|
-
const publicProof = await client.verify({
|
|
94
|
-
verifier: 'ownership-basic',
|
|
95
|
-
content: 'Public content',
|
|
96
|
-
options: { privacyLevel: 'public' }
|
|
97
|
-
});
|
|
67
|
+
Use the API directly (avoids drift):
|
|
98
68
|
|
|
99
|
-
|
|
100
|
-
const privateProof = await client.verify({
|
|
101
|
-
verifier: 'ownership-basic',
|
|
102
|
-
content: 'Private content',
|
|
103
|
-
options: { privacyLevel: 'private' }
|
|
104
|
-
});
|
|
105
|
-
```
|
|
69
|
+
- `GET /api/v1/verification/verifiers`
|
|
106
70
|
|
|
107
|
-
##
|
|
71
|
+
## Gate checks (recommended for server-side gating)
|
|
108
72
|
|
|
109
|
-
|
|
73
|
+
For production server-side gating, prefer the minimal public endpoint:
|
|
110
74
|
|
|
111
75
|
```javascript
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
76
|
+
const res = await client.gateCheck({
|
|
77
|
+
address: '0x...',
|
|
78
|
+
verifierIds: ['token-holding'],
|
|
79
|
+
contractAddress: '0x...',
|
|
80
|
+
minBalance: '100',
|
|
81
|
+
chainId: 1,
|
|
82
|
+
// Optional: require a recent proof for point-in-time verifiers (example: last hour)
|
|
83
|
+
since: Date.now() - 60 * 60 * 1000
|
|
118
84
|
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## Error Handling
|
|
122
85
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const proof = await client.verify({
|
|
126
|
-
verifier: 'ownership-basic',
|
|
127
|
-
content: 'Hello NEUS'
|
|
128
|
-
});
|
|
129
|
-
} catch (error) {
|
|
130
|
-
if (error.code === 4001) {
|
|
131
|
-
console.log('User cancelled verification');
|
|
132
|
-
} else {
|
|
133
|
-
console.error('Verification failed:', error.message);
|
|
134
|
-
}
|
|
86
|
+
if (!res.data?.eligible) {
|
|
87
|
+
throw new Error('Access denied');
|
|
135
88
|
}
|
|
136
89
|
```
|
|
137
90
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
### `verify(params)`
|
|
141
|
-
|
|
142
|
-
Create verification proof.
|
|
143
|
-
|
|
144
|
-
**Parameters:**
|
|
145
|
-
- `verifier` (string) - Verifier ID
|
|
146
|
-
- `content` (string) - Content to verify (for ownership-basic)
|
|
147
|
-
- `data` (object) - Verifier-specific data
|
|
148
|
-
- `options` (object) - Privacy and storage options
|
|
149
|
-
|
|
150
|
-
**Returns:** `{ qHash, status, data }`
|
|
151
|
-
|
|
152
|
-
### `getStatus(qHash)`
|
|
91
|
+
Note: `gateCheck` evaluates **existing public/discoverable proofs**. For strict real-time decisions, create a new proof via `client.verify(...)` (or `POST /api/v1/verification`) and use the final status.
|
|
153
92
|
|
|
154
|
-
|
|
93
|
+
## Lookup mode (Premium, server-side only; non-persistent)
|
|
155
94
|
|
|
156
|
-
**
|
|
157
|
-
- `qHash` (string) - Proof identifier
|
|
95
|
+
If you need a **real-time assessment** without minting/storing proofs (no `qHash`), use lookup mode:
|
|
158
96
|
|
|
159
|
-
**
|
|
97
|
+
- **Endpoint:** `POST /api/v1/verification/lookup`
|
|
98
|
+
- **Auth:** `Authorization: Bearer sk_live_...` (or `sk_test_...`)
|
|
99
|
+
- **Semantics:** runs `external_lookup` verifiers only; **does not** create a proof record
|
|
160
100
|
|
|
161
|
-
|
|
101
|
+
Note: lookup mode is deployment-dependent and is not part of the stable public integrator OpenAPI (`docs/api/public-api.json`).
|
|
162
102
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
### `pollProofStatus(qHash, options)`
|
|
172
|
-
|
|
173
|
-
Poll until verification completes.
|
|
174
|
-
|
|
175
|
-
**Parameters:**
|
|
176
|
-
- `qHash` (string) - Proof identifier
|
|
177
|
-
- `options` (object) - Polling configuration
|
|
178
|
-
- `interval` (number) - Polling interval in ms
|
|
179
|
-
- `timeout` (number) - Total timeout in ms
|
|
180
|
-
- `onProgress` (function) - Progress callback
|
|
181
|
-
|
|
182
|
-
**Returns:** `{ success, status, data }`
|
|
103
|
+
```javascript
|
|
104
|
+
const res = await client.lookup({
|
|
105
|
+
// Premium API key (keep server-side only)
|
|
106
|
+
apiKey: process.env.NEUS_API_KEY,
|
|
107
|
+
verifierIds: ['wallet-risk'],
|
|
108
|
+
targetWalletAddress: '0x...',
|
|
109
|
+
data: { chainId: 1 }
|
|
110
|
+
});
|
|
183
111
|
|
|
184
|
-
|
|
112
|
+
if (!res.data?.verified) {
|
|
113
|
+
throw new Error('Rejected');
|
|
114
|
+
}
|
|
115
|
+
```
|
|
185
116
|
|
|
186
|
-
|
|
117
|
+
Note: `gateCheck()` and `lookup()` are different tools.
|
|
118
|
+
- Use **`gateCheck()`** when you want to gate based on **existing public/discoverable proofs** (fast, minimal response).
|
|
119
|
+
- Use **`lookup()`** when you want a **fresh, non-persistent** decision (typically billable in hosted deployments).
|
|
120
|
+
- Only combine them if you are intentionally doing a cache-first strategy (gate-check first to avoid unnecessary lookups).
|
|
187
121
|
|
|
188
|
-
|
|
122
|
+
## Private proof reads (owner)
|
|
189
123
|
|
|
190
|
-
|
|
124
|
+
- Private proof by Proof ID (qHash): `client.getPrivateStatus(qHash, wallet)`
|
|
125
|
+
- Private proofs by wallet/DID: `client.getPrivateProofsByWallet(walletOrDid, { limit, offset }, wallet)`
|
|
191
126
|
|
|
192
|
-
|
|
127
|
+
## React widgets
|
|
193
128
|
|
|
194
|
-
|
|
129
|
+
For UI gating, see `./widgets/README.md`.
|
|
195
130
|
|
|
196
|
-
|
|
131
|
+
Widget imports:
|
|
197
132
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
133
|
+
```javascript
|
|
134
|
+
import { VerifyGate, ProofBadge } from '@neus/sdk/widgets';
|
|
135
|
+
```
|
|
201
136
|
|
|
202
|
-
##
|
|
137
|
+
## Reference docs
|
|
203
138
|
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
- **[GitHub Issues](https://github.com/neus/network/issues)** - Community support
|
|
139
|
+
- API Reference: `../docs/api/README.md`
|
|
140
|
+
- OpenAPI (JSON): `../docs/api/public-api.json`
|
package/SECURITY.md
CHANGED
|
@@ -1,224 +1,29 @@
|
|
|
1
|
-
# NEUS SDK
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
async verify(data, options) {
|
|
31
|
-
// Validate address format
|
|
32
|
-
if (!ethers.isAddress(data.contractAddress)) {
|
|
33
|
-
throw new ValidationError('Invalid contract address');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Sanitize content
|
|
37
|
-
const sanitizedContent = data.content.trim().slice(0, 1000);
|
|
38
|
-
|
|
39
|
-
// Verify required fields (owner for ownership-basic/licensed, ownerAddress for nft-ownership/token-holding)
|
|
40
|
-
if ((!data.owner && !data.ownerAddress) || !data.reference) {
|
|
41
|
-
throw new ValidationError('Missing required fields');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// WRONG: Direct usage without validation
|
|
46
|
-
async verify(data, options) {
|
|
47
|
-
const result = await contract.balanceOf(data.address); // Unsafe!
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 2. External API Security
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
// CORRECT: Rate limiting and error handling
|
|
55
|
-
class ExternalVerifier {
|
|
56
|
-
constructor() {
|
|
57
|
-
this.rateLimiter = new Map();
|
|
58
|
-
this.maxRequests = 100; // per hour
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async callExternalAPI(userId) {
|
|
62
|
-
// Check rate limits
|
|
63
|
-
if (this.isRateLimited(userId)) {
|
|
64
|
-
throw new Error('Rate limit exceeded');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const result = await fetch(url, { timeout: 5000 });
|
|
69
|
-
return result;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// Don't expose internal errors
|
|
72
|
-
throw new Error('External verification failed');
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 3. Smart Contract Interaction
|
|
79
|
-
|
|
80
|
-
```javascript
|
|
81
|
-
// CORRECT: Verify contract bytecode
|
|
82
|
-
async verifyContract(address, expectedBytecode) {
|
|
83
|
-
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
|
84
|
-
const code = await provider.getCode(address);
|
|
85
|
-
|
|
86
|
-
if (code === '0x') {
|
|
87
|
-
throw new Error('No contract at address');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Optionally verify against known bytecode
|
|
91
|
-
if (expectedBytecode && code !== expectedBytecode) {
|
|
92
|
-
throw new Error('Contract bytecode mismatch');
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Common Attack Vectors
|
|
98
|
-
|
|
99
|
-
### 1. Proof Spoofing
|
|
100
|
-
|
|
101
|
-
**Risk**: Malicious users attempting to forge verification results
|
|
102
|
-
|
|
103
|
-
**Mitigation**:
|
|
104
|
-
- Always verify ownership through on-chain data or cryptographic signatures
|
|
105
|
-
- Never trust client-provided verification results
|
|
106
|
-
- Use the protocol's signature verification for all critical operations
|
|
107
|
-
- Use `verifierContentHash` for proof-of-existence; avoid publishing full content unless explicitly intended
|
|
108
|
-
|
|
109
|
-
### 2. Replay Attacks
|
|
110
|
-
|
|
111
|
-
**Risk**: Reusing old signatures or proofs
|
|
112
|
-
|
|
113
|
-
**Mitigation**:
|
|
114
|
-
- Built-in: 5-minute timestamp validation and anti-replay protections
|
|
115
|
-
- Additional: Include chain-specific data in verification
|
|
116
|
-
|
|
117
|
-
### 3. Unintended Data Exposure
|
|
118
|
-
|
|
119
|
-
**Risk**: Accidentally exposing private content in public snapshots
|
|
120
|
-
|
|
121
|
-
**Mitigation**:
|
|
122
|
-
- Set `privacyLevel: 'private'` and avoid `publicDisplay`/`storeOriginalContent`
|
|
123
|
-
- For anchoring without exposure, use `enableIpfs: true` with `publicDisplay: false`, `storeOriginalContent: false`
|
|
124
|
-
- Ensure UI defaults use secure privacy settings
|
|
125
|
-
|
|
126
|
-
### 4. Contract Upgrades
|
|
127
|
-
|
|
128
|
-
**Risk**: Verified contracts changing implementation
|
|
129
|
-
|
|
130
|
-
**Mitigation**:
|
|
131
|
-
- Store contract address AND block number in proof
|
|
132
|
-
- Consider proxy pattern detection
|
|
133
|
-
- Document upgrade implications for users
|
|
134
|
-
|
|
135
|
-
## Rate Limiting Guidelines
|
|
136
|
-
|
|
137
|
-
### External APIs
|
|
138
|
-
|
|
139
|
-
| Service Type | Recommended Limit | Timeout |
|
|
140
|
-
|-------------|------------------|---------|
|
|
141
|
-
| Blockchain RPC | 100 req/sec | 10s |
|
|
142
|
-
| Social APIs | 10 req/min | 5s |
|
|
143
|
-
| DNS Lookups | 50 req/min | 3s |
|
|
144
|
-
| IPFS Gateway | 30 req/min | 30s |
|
|
145
|
-
|
|
146
|
-
### Implementation Example
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
class RateLimiter {
|
|
150
|
-
constructor(maxRequests, windowMs) {
|
|
151
|
-
this.requests = new Map();
|
|
152
|
-
this.maxRequests = maxRequests;
|
|
153
|
-
this.windowMs = windowMs;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
allow(identifier) {
|
|
157
|
-
const now = Date.now();
|
|
158
|
-
const requests = this.requests.get(identifier) || [];
|
|
159
|
-
|
|
160
|
-
// Clean old requests
|
|
161
|
-
const valid = requests.filter(t => now - t < this.windowMs);
|
|
162
|
-
|
|
163
|
-
if (valid.length >= this.maxRequests) {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
valid.push(now);
|
|
168
|
-
this.requests.set(identifier, valid);
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Error Handling
|
|
175
|
-
|
|
176
|
-
### Security-First Error Messages
|
|
177
|
-
|
|
178
|
-
```javascript
|
|
179
|
-
// CORRECT: Generic external errors
|
|
180
|
-
catch (error) {
|
|
181
|
-
logger.error('Verification failed', {
|
|
182
|
-
error: error.message,
|
|
183
|
-
userId: data.owner
|
|
184
|
-
});
|
|
185
|
-
throw new Error('Verification failed');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// WRONG: Exposing internal details
|
|
189
|
-
catch (error) {
|
|
190
|
-
throw new Error(`Database query failed: ${error.stack}`);
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## Reporting Security Issues
|
|
195
|
-
|
|
196
|
-
Found a security vulnerability? Please report it responsibly:
|
|
197
|
-
|
|
198
|
-
1. **DO NOT** create public GitHub issues for security vulnerabilities
|
|
199
|
-
2. Email: dev@neus.network
|
|
200
|
-
3. Include:
|
|
201
|
-
- Description of the vulnerability
|
|
202
|
-
- Steps to reproduce
|
|
203
|
-
- Potential impact
|
|
204
|
-
- Suggested fix (if applicable)
|
|
205
|
-
|
|
206
|
-
## Security Updates
|
|
207
|
-
|
|
208
|
-
Monitor security updates:
|
|
209
|
-
- GitHub Security Advisories: https://github.com/neus/network/security
|
|
210
|
-
- NPM Audit: Run `npm audit` regularly
|
|
211
|
-
- Email updates: dev@neus.network
|
|
212
|
-
|
|
213
|
-
## Compliance
|
|
214
|
-
|
|
215
|
-
The NEUS Network is designed for:
|
|
216
|
-
- GDPR compliance (no PII storage by default)
|
|
217
|
-
- Cryptographic proof integrity
|
|
218
|
-
- Decentralized trust model
|
|
219
|
-
|
|
220
|
-
However, verifier implementations must ensure their own compliance based on data handled.
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
*Version: 1.0.0*
|
|
1
|
+
# NEUS SDK security notes
|
|
2
|
+
|
|
3
|
+
Treat **wallet signatures** and **API keys** as secrets. Do not log them, expose them to clients, or store them in analytics.
|
|
4
|
+
|
|
5
|
+
## Authentication model (public surface)
|
|
6
|
+
|
|
7
|
+
- **Verification submission** (`POST /api/v1/verification`) is authenticated by a signature over the **NEUS Standard Signing String**.
|
|
8
|
+
- **Status by Proof ID (qHash)** (`GET /api/v1/verification/status/{qHash}`) is safe to call publicly.
|
|
9
|
+
- **Owner-only reads** of private proof payloads require an additional owner signature. The SDK uses:
|
|
10
|
+
- `x-wallet-address`
|
|
11
|
+
- `x-signature`
|
|
12
|
+
- `x-signed-timestamp`
|
|
13
|
+
|
|
14
|
+
## Do not
|
|
15
|
+
|
|
16
|
+
- Do not treat proof signatures as bearer tokens (they are request-bound).
|
|
17
|
+
- Do not embed API keys in browser apps. Keep API keys server-side only.
|
|
18
|
+
- Do not log or persist:
|
|
19
|
+
- proof signatures
|
|
20
|
+
- API keys
|
|
21
|
+
- third-party auth credentials or provider tokens (if your integration uses them)
|
|
22
|
+
|
|
23
|
+
## Recommended privacy defaults
|
|
24
|
+
|
|
25
|
+
- `privacyLevel: 'private'`
|
|
26
|
+
- `publicDisplay: false`
|
|
27
|
+
- `storeOriginalContent: false`
|
|
28
|
+
|
|
29
|
+
“Discoverable” proofs are **public** (`privacyLevel='public'`) and explicitly opted into discovery (`publicDisplay=true`).
|