@nostrify/policies 0.36.5 → 0.36.6
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/.turbo/turbo-build.log +28 -5
- package/.turbo/turbo-setup.log +22 -0
- package/.turbo/turbo-test.log +4 -0
- package/AntiDuplicationPolicy.test.ts +54 -41
- package/AntiDuplicationPolicy.ts +7 -3
- package/AnyPolicy.test.ts +15 -14
- package/AnyPolicy.ts +5 -2
- package/AuthorPolicy.test.ts +8 -7
- package/AuthorPolicy.ts +9 -3
- package/CHANGELOG.md +9 -0
- package/DomainPolicy.test.ts +130 -77
- package/DomainPolicy.ts +3 -3
- package/FiltersPolicy.test.ts +14 -7
- package/FiltersPolicy.ts +5 -2
- package/HashtagPolicy.test.ts +25 -14
- package/HashtagPolicy.ts +5 -2
- package/HellthreadPolicy.test.ts +10 -9
- package/HellthreadPolicy.ts +6 -3
- package/InvertPolicy.test.ts +10 -9
- package/InvertPolicy.ts +8 -2
- package/KeywordPolicy.test.ts +18 -12
- package/KeywordPolicy.ts +5 -2
- package/NoOpPolicy.test.ts +8 -7
- package/NoOpPolicy.ts +1 -1
- package/OpenAIPolicy.test.ts +22 -9
- package/OpenAIPolicy.ts +5 -2
- package/PipePolicy.test.ts +18 -17
- package/PipePolicy.ts +5 -2
- package/PowPolicy.test.ts +14 -13
- package/PowPolicy.ts +6 -3
- package/PubkeyBanPolicy.test.ts +15 -8
- package/PubkeyBanPolicy.ts +5 -2
- package/ReadOnlyPolicy.test.ts +9 -8
- package/ReadOnlyPolicy.ts +1 -1
- package/RegexPolicy.test.ts +19 -10
- package/RegexPolicy.ts +5 -2
- package/ReplyBotPolicy.test.ts +43 -27
- package/ReplyBotPolicy.ts +6 -3
- package/SizePolicy.test.ts +9 -8
- package/SizePolicy.ts +6 -2
- package/WhitelistPolicy.test.ts +15 -8
- package/WhitelistPolicy.ts +6 -2
- package/WoTPolicy.test.ts +48 -22
- package/WoTPolicy.ts +5 -2
- package/dist/AntiDuplicationPolicy.d.ts +2 -2
- package/dist/AntiDuplicationPolicy.d.ts.map +1 -1
- package/dist/AntiDuplicationPolicy.js +41 -56
- package/dist/AnyPolicy.d.ts +1 -1
- package/dist/AnyPolicy.d.ts.map +1 -1
- package/dist/AnyPolicy.js +17 -16
- package/dist/AuthorPolicy.d.ts +1 -1
- package/dist/AuthorPolicy.d.ts.map +1 -1
- package/dist/AuthorPolicy.js +19 -20
- package/dist/DomainPolicy.d.ts +2 -2
- package/dist/DomainPolicy.d.ts.map +1 -1
- package/dist/DomainPolicy.js +57 -59
- package/dist/FiltersPolicy.d.ts +1 -1
- package/dist/FiltersPolicy.d.ts.map +1 -1
- package/dist/FiltersPolicy.js +15 -24
- package/dist/HashtagPolicy.d.ts +1 -1
- package/dist/HashtagPolicy.d.ts.map +1 -1
- package/dist/HashtagPolicy.js +16 -23
- package/dist/HellthreadPolicy.d.ts +1 -1
- package/dist/HellthreadPolicy.d.ts.map +1 -1
- package/dist/HellthreadPolicy.js +18 -17
- package/dist/InvertPolicy.d.ts +1 -1
- package/dist/InvertPolicy.d.ts.map +1 -1
- package/dist/InvertPolicy.js +18 -18
- package/dist/KeywordPolicy.d.ts +1 -1
- package/dist/KeywordPolicy.d.ts.map +1 -1
- package/dist/KeywordPolicy.js +16 -23
- package/dist/NoOpPolicy.d.ts +1 -1
- package/dist/NoOpPolicy.d.ts.map +1 -1
- package/dist/NoOpPolicy.js +8 -7
- package/dist/OpenAIPolicy.d.ts +1 -1
- package/dist/OpenAIPolicy.d.ts.map +1 -1
- package/dist/OpenAIPolicy.js +35 -55
- package/dist/PipePolicy.d.ts +1 -1
- package/dist/PipePolicy.d.ts.map +1 -1
- package/dist/PipePolicy.js +16 -33
- package/dist/PowPolicy.d.ts +1 -1
- package/dist/PowPolicy.d.ts.map +1 -1
- package/dist/PowPolicy.js +25 -30
- package/dist/PubkeyBanPolicy.d.ts +1 -1
- package/dist/PubkeyBanPolicy.d.ts.map +1 -1
- package/dist/PubkeyBanPolicy.js +16 -22
- package/dist/ReadOnlyPolicy.d.ts +1 -1
- package/dist/ReadOnlyPolicy.d.ts.map +1 -1
- package/dist/ReadOnlyPolicy.js +8 -7
- package/dist/RegexPolicy.d.ts +1 -1
- package/dist/RegexPolicy.d.ts.map +1 -1
- package/dist/RegexPolicy.js +14 -20
- package/dist/ReplyBotPolicy.d.ts +1 -1
- package/dist/ReplyBotPolicy.d.ts.map +1 -1
- package/dist/ReplyBotPolicy.js +39 -38
- package/dist/SizePolicy.d.ts +1 -1
- package/dist/SizePolicy.d.ts.map +1 -1
- package/dist/SizePolicy.js +17 -25
- package/dist/WhitelistPolicy.d.ts +1 -1
- package/dist/WhitelistPolicy.d.ts.map +1 -1
- package/dist/WhitelistPolicy.js +23 -29
- package/dist/WoTPolicy.d.ts +2 -2
- package/dist/WoTPolicy.d.ts.map +1 -1
- package/dist/WoTPolicy.js +34 -33
- package/dist/mod.d.ts +20 -20
- package/dist/mod.js +42 -21
- package/dist/mod.js.map +7 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/mod.ts +20 -20
- package/package.json +8 -6
- package/tsconfig.json +3 -1
- package/.turbo/daemon/7bb8240f68f7ad88-turbo.log.2025-07-29 +0 -0
- package/dist/AntiDuplicationPolicy.js.map +0 -1
- package/dist/AnyPolicy.js.map +0 -1
- package/dist/AuthorPolicy.js.map +0 -1
- package/dist/DomainPolicy.js.map +0 -1
- package/dist/FiltersPolicy.js.map +0 -1
- package/dist/HashtagPolicy.js.map +0 -1
- package/dist/HellthreadPolicy.js.map +0 -1
- package/dist/InvertPolicy.js.map +0 -1
- package/dist/KeywordPolicy.js.map +0 -1
- package/dist/NoOpPolicy.js.map +0 -1
- package/dist/OpenAIPolicy.js.map +0 -1
- package/dist/PipePolicy.js.map +0 -1
- package/dist/PowPolicy.js.map +0 -1
- package/dist/PubkeyBanPolicy.js.map +0 -1
- package/dist/ReadOnlyPolicy.js.map +0 -1
- package/dist/RegexPolicy.js.map +0 -1
- package/dist/ReplyBotPolicy.js.map +0 -1
- package/dist/SizePolicy.js.map +0 -1
- package/dist/WhitelistPolicy.js.map +0 -1
- package/dist/WoTPolicy.js.map +0 -1
package/DomainPolicy.test.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { genEvent, MockRelay } from "@nostrify/nostrify/test";
|
|
3
|
+
import type { NostrMetadata } from "@nostrify/types";
|
|
4
|
+
import { deepStrictEqual } from "node:assert";
|
|
5
|
+
import { generateSecretKey, getPublicKey } from "nostr-tools";
|
|
5
6
|
|
|
6
|
-
import { DomainPolicy } from
|
|
7
|
+
import { DomainPolicy } from "./DomainPolicy.ts";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
await test("DomainPolicy allows events from authors with a valid nip05", async () => {
|
|
9
10
|
const sk = generateSecretKey();
|
|
10
11
|
const pubkey = getPublicKey(sk);
|
|
11
12
|
|
|
@@ -13,62 +14,73 @@ Deno.test('DomainPolicy allows events from authors with a valid nip05', async ()
|
|
|
13
14
|
const policy = new DomainPolicy(store, {
|
|
14
15
|
// deno-lint-ignore require-await
|
|
15
16
|
async lookup(nip05: string) {
|
|
16
|
-
if (nip05 ===
|
|
17
|
+
if (nip05 === "alex@gleasonator.dev") {
|
|
17
18
|
return { pubkey };
|
|
18
19
|
} else {
|
|
19
|
-
throw new Error(
|
|
20
|
+
throw new Error("not found");
|
|
20
21
|
}
|
|
21
22
|
},
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
const metadata: NostrMetadata = { nip05:
|
|
25
|
-
await store.event(
|
|
26
|
-
|
|
25
|
+
const metadata: NostrMetadata = { nip05: "alex@gleasonator.dev" };
|
|
26
|
+
await store.event(
|
|
27
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
28
|
+
);
|
|
29
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
27
30
|
|
|
28
31
|
const result = await policy.call(event);
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
deepStrictEqual(result, ["OK", event.id, true, ""]);
|
|
31
34
|
});
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
await test("DomainPolicy rejects events from authors without a kind 0", async () => {
|
|
34
37
|
const store = new MockRelay();
|
|
35
38
|
const policy = new DomainPolicy(store);
|
|
36
|
-
const event = genEvent({ kind: 1, content:
|
|
39
|
+
const event = genEvent({ kind: 1, content: "hello world" });
|
|
37
40
|
|
|
38
41
|
const result = await policy.call(event);
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
deepStrictEqual(result, [
|
|
44
|
+
"OK",
|
|
45
|
+
event.id,
|
|
46
|
+
false,
|
|
47
|
+
"blocked: author is missing a kind 0 event",
|
|
48
|
+
]);
|
|
41
49
|
});
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
await test("DomainPolicy rejects events from authors with a missing nip05", async () => {
|
|
44
52
|
const store = new MockRelay();
|
|
45
53
|
const policy = new DomainPolicy(store);
|
|
46
54
|
|
|
47
55
|
const sk = generateSecretKey();
|
|
48
56
|
const metadata: NostrMetadata = {};
|
|
49
|
-
await store.event(
|
|
50
|
-
|
|
57
|
+
await store.event(
|
|
58
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
59
|
+
);
|
|
60
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
51
61
|
|
|
52
62
|
const result = await policy.call(event);
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
deepStrictEqual(result, ["OK", event.id, false, "blocked: missing nip05"]);
|
|
55
65
|
});
|
|
56
66
|
|
|
57
|
-
|
|
67
|
+
await test("DomainPolicy rejects events from authors with a malformed nip05", async () => {
|
|
58
68
|
const store = new MockRelay();
|
|
59
69
|
const policy = new DomainPolicy(store);
|
|
60
70
|
|
|
61
71
|
const sk = generateSecretKey();
|
|
62
|
-
const metadata: NostrMetadata = { nip05:
|
|
63
|
-
await store.event(
|
|
64
|
-
|
|
72
|
+
const metadata: NostrMetadata = { nip05: "asdf" };
|
|
73
|
+
await store.event(
|
|
74
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
75
|
+
);
|
|
76
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
65
77
|
|
|
66
78
|
const result = await policy.call(event);
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
deepStrictEqual(result, ["OK", event.id, false, "blocked: missing nip05"]);
|
|
69
81
|
});
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
await test("DomainPolicy rejects events from authors with an invalid nip05", async () => {
|
|
72
84
|
const store = new MockRelay();
|
|
73
85
|
|
|
74
86
|
const policy = new DomainPolicy(store, {
|
|
@@ -79,17 +91,24 @@ Deno.test('DomainPolicy rejects events from authors with an invalid nip05', asyn
|
|
|
79
91
|
},
|
|
80
92
|
});
|
|
81
93
|
|
|
82
|
-
const metadata: NostrMetadata = { nip05:
|
|
94
|
+
const metadata: NostrMetadata = { nip05: "alex@gleasonator.dev" };
|
|
83
95
|
const sk = generateSecretKey();
|
|
84
|
-
await store.event(
|
|
85
|
-
|
|
96
|
+
await store.event(
|
|
97
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
98
|
+
);
|
|
99
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
86
100
|
|
|
87
101
|
const result = await policy.call(event);
|
|
88
102
|
|
|
89
|
-
|
|
103
|
+
deepStrictEqual(result, [
|
|
104
|
+
"OK",
|
|
105
|
+
event.id,
|
|
106
|
+
false,
|
|
107
|
+
"blocked: mismatched nip05 pubkey",
|
|
108
|
+
]);
|
|
90
109
|
});
|
|
91
110
|
|
|
92
|
-
|
|
111
|
+
await test("DomainPolicy rejects events from authors with a blacklisted nip05 domain", async () => {
|
|
93
112
|
const sk = generateSecretKey();
|
|
94
113
|
const pubkey = getPublicKey(sk);
|
|
95
114
|
|
|
@@ -97,25 +116,32 @@ Deno.test('DomainPolicy rejects events from authors with a blacklisted nip05 dom
|
|
|
97
116
|
const policy = new DomainPolicy(store, {
|
|
98
117
|
// deno-lint-ignore require-await
|
|
99
118
|
async lookup(nip05: string) {
|
|
100
|
-
if (nip05 ===
|
|
119
|
+
if (nip05 === "bot@replyguy.dev") {
|
|
101
120
|
return { pubkey };
|
|
102
121
|
} else {
|
|
103
|
-
throw new Error(
|
|
122
|
+
throw new Error("not found");
|
|
104
123
|
}
|
|
105
124
|
},
|
|
106
|
-
blacklist: [
|
|
125
|
+
blacklist: ["replyguy.dev"],
|
|
107
126
|
});
|
|
108
127
|
|
|
109
|
-
const metadata: NostrMetadata = { nip05:
|
|
110
|
-
await store.event(
|
|
111
|
-
|
|
128
|
+
const metadata: NostrMetadata = { nip05: "bot@replyguy.dev" };
|
|
129
|
+
await store.event(
|
|
130
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
131
|
+
);
|
|
132
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
112
133
|
|
|
113
134
|
const result = await policy.call(event);
|
|
114
135
|
|
|
115
|
-
|
|
136
|
+
deepStrictEqual(result, [
|
|
137
|
+
"OK",
|
|
138
|
+
event.id,
|
|
139
|
+
false,
|
|
140
|
+
"blocked: blacklisted nip05 domain",
|
|
141
|
+
]);
|
|
116
142
|
});
|
|
117
143
|
|
|
118
|
-
|
|
144
|
+
await test("DomainPolicy rejects events from authors who aren't on a whitelisted domain", async () => {
|
|
119
145
|
const sk = generateSecretKey();
|
|
120
146
|
const pubkey = getPublicKey(sk);
|
|
121
147
|
|
|
@@ -123,25 +149,32 @@ Deno.test("DomainPolicy rejects events from authors who aren't on a whitelisted
|
|
|
123
149
|
const policy = new DomainPolicy(store, {
|
|
124
150
|
// deno-lint-ignore require-await
|
|
125
151
|
async lookup(nip05: string) {
|
|
126
|
-
if (nip05 ===
|
|
152
|
+
if (nip05 === "bot@replyguy.dev") {
|
|
127
153
|
return { pubkey };
|
|
128
154
|
} else {
|
|
129
|
-
throw new Error(
|
|
155
|
+
throw new Error("not found");
|
|
130
156
|
}
|
|
131
157
|
},
|
|
132
|
-
whitelist: [
|
|
158
|
+
whitelist: ["gleasonator.dev"],
|
|
133
159
|
});
|
|
134
160
|
|
|
135
|
-
const metadata: NostrMetadata = { nip05:
|
|
136
|
-
await store.event(
|
|
137
|
-
|
|
161
|
+
const metadata: NostrMetadata = { nip05: "bot@replyguy.dev" };
|
|
162
|
+
await store.event(
|
|
163
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
164
|
+
);
|
|
165
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
138
166
|
|
|
139
167
|
const result = await policy.call(event);
|
|
140
168
|
|
|
141
|
-
|
|
169
|
+
deepStrictEqual(result, [
|
|
170
|
+
"OK",
|
|
171
|
+
event.id,
|
|
172
|
+
false,
|
|
173
|
+
"blocked: nip05 domain not in whitelist",
|
|
174
|
+
]);
|
|
142
175
|
});
|
|
143
176
|
|
|
144
|
-
|
|
177
|
+
await test("DomainPolicy allows events from authors who are on a whitelisted domain", async () => {
|
|
145
178
|
const sk = generateSecretKey();
|
|
146
179
|
const pubkey = getPublicKey(sk);
|
|
147
180
|
|
|
@@ -149,25 +182,27 @@ Deno.test('DomainPolicy allows events from authors who are on a whitelisted doma
|
|
|
149
182
|
const policy = new DomainPolicy(store, {
|
|
150
183
|
// deno-lint-ignore require-await
|
|
151
184
|
async lookup(nip05: string) {
|
|
152
|
-
if (nip05 ===
|
|
185
|
+
if (nip05 === "alex@gleasonator.dev") {
|
|
153
186
|
return { pubkey };
|
|
154
187
|
} else {
|
|
155
|
-
throw new Error(
|
|
188
|
+
throw new Error("not found");
|
|
156
189
|
}
|
|
157
190
|
},
|
|
158
|
-
whitelist: [
|
|
191
|
+
whitelist: ["gleasonator.dev"],
|
|
159
192
|
});
|
|
160
193
|
|
|
161
|
-
const metadata: NostrMetadata = { nip05:
|
|
162
|
-
await store.event(
|
|
163
|
-
|
|
194
|
+
const metadata: NostrMetadata = { nip05: "alex@gleasonator.dev" };
|
|
195
|
+
await store.event(
|
|
196
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
197
|
+
);
|
|
198
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
164
199
|
|
|
165
200
|
const result = await policy.call(event);
|
|
166
201
|
|
|
167
|
-
|
|
202
|
+
deepStrictEqual(result, ["OK", event.id, true, ""]);
|
|
168
203
|
});
|
|
169
204
|
|
|
170
|
-
|
|
205
|
+
await test("DomainPolicy rejects events from authors with a subdomain of a blacklisted domain", async () => {
|
|
171
206
|
const sk = generateSecretKey();
|
|
172
207
|
const pubkey = getPublicKey(sk);
|
|
173
208
|
|
|
@@ -175,25 +210,32 @@ Deno.test('DomainPolicy rejects events from authors with a subdomain of a blackl
|
|
|
175
210
|
const policy = new DomainPolicy(store, {
|
|
176
211
|
// deno-lint-ignore require-await
|
|
177
212
|
async lookup(nip05: string) {
|
|
178
|
-
if (nip05 ===
|
|
213
|
+
if (nip05 === "bot@spam.replyguy.dev") {
|
|
179
214
|
return { pubkey };
|
|
180
215
|
} else {
|
|
181
|
-
throw new Error(
|
|
216
|
+
throw new Error("not found");
|
|
182
217
|
}
|
|
183
218
|
},
|
|
184
|
-
blacklist: [
|
|
219
|
+
blacklist: ["replyguy.dev"],
|
|
185
220
|
});
|
|
186
221
|
|
|
187
|
-
const metadata: NostrMetadata = { nip05:
|
|
188
|
-
await store.event(
|
|
189
|
-
|
|
222
|
+
const metadata: NostrMetadata = { nip05: "bot@spam.replyguy.dev" };
|
|
223
|
+
await store.event(
|
|
224
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
225
|
+
);
|
|
226
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
190
227
|
|
|
191
228
|
const result = await policy.call(event);
|
|
192
229
|
|
|
193
|
-
|
|
230
|
+
deepStrictEqual(result, [
|
|
231
|
+
"OK",
|
|
232
|
+
event.id,
|
|
233
|
+
false,
|
|
234
|
+
"blocked: blacklisted nip05 domain",
|
|
235
|
+
]);
|
|
194
236
|
});
|
|
195
237
|
|
|
196
|
-
|
|
238
|
+
await test("DomainPolicy rejects events from authors with a deeply nested subdomain of a blacklisted domain", async () => {
|
|
197
239
|
const sk = generateSecretKey();
|
|
198
240
|
const pubkey = getPublicKey(sk);
|
|
199
241
|
|
|
@@ -201,25 +243,34 @@ Deno.test('DomainPolicy rejects events from authors with a deeply nested subdoma
|
|
|
201
243
|
const policy = new DomainPolicy(store, {
|
|
202
244
|
// deno-lint-ignore require-await
|
|
203
245
|
async lookup(nip05: string) {
|
|
204
|
-
if (nip05 ===
|
|
246
|
+
if (nip05 === "user@deep.nested.spam.replyguy.dev") {
|
|
205
247
|
return { pubkey };
|
|
206
248
|
} else {
|
|
207
|
-
throw new Error(
|
|
249
|
+
throw new Error("not found");
|
|
208
250
|
}
|
|
209
251
|
},
|
|
210
|
-
blacklist: [
|
|
252
|
+
blacklist: ["replyguy.dev"],
|
|
211
253
|
});
|
|
212
254
|
|
|
213
|
-
const metadata: NostrMetadata = {
|
|
214
|
-
|
|
215
|
-
|
|
255
|
+
const metadata: NostrMetadata = {
|
|
256
|
+
nip05: "user@deep.nested.spam.replyguy.dev",
|
|
257
|
+
};
|
|
258
|
+
await store.event(
|
|
259
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
260
|
+
);
|
|
261
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
216
262
|
|
|
217
263
|
const result = await policy.call(event);
|
|
218
264
|
|
|
219
|
-
|
|
265
|
+
deepStrictEqual(result, [
|
|
266
|
+
"OK",
|
|
267
|
+
event.id,
|
|
268
|
+
false,
|
|
269
|
+
"blocked: blacklisted nip05 domain",
|
|
270
|
+
]);
|
|
220
271
|
});
|
|
221
272
|
|
|
222
|
-
|
|
273
|
+
await test("DomainPolicy allows events from authors with similar but not subdomain of blacklisted domain", async () => {
|
|
223
274
|
const sk = generateSecretKey();
|
|
224
275
|
const pubkey = getPublicKey(sk);
|
|
225
276
|
|
|
@@ -227,20 +278,22 @@ Deno.test('DomainPolicy allows events from authors with similar but not subdomai
|
|
|
227
278
|
const policy = new DomainPolicy(store, {
|
|
228
279
|
// deno-lint-ignore require-await
|
|
229
280
|
async lookup(nip05: string) {
|
|
230
|
-
if (nip05 ===
|
|
281
|
+
if (nip05 === "user@notreplyguy.dev") {
|
|
231
282
|
return { pubkey };
|
|
232
283
|
} else {
|
|
233
|
-
throw new Error(
|
|
284
|
+
throw new Error("not found");
|
|
234
285
|
}
|
|
235
286
|
},
|
|
236
|
-
blacklist: [
|
|
287
|
+
blacklist: ["replyguy.dev"],
|
|
237
288
|
});
|
|
238
289
|
|
|
239
|
-
const metadata: NostrMetadata = { nip05:
|
|
240
|
-
await store.event(
|
|
241
|
-
|
|
290
|
+
const metadata: NostrMetadata = { nip05: "user@notreplyguy.dev" };
|
|
291
|
+
await store.event(
|
|
292
|
+
genEvent({ kind: 0, content: JSON.stringify(metadata) }, sk),
|
|
293
|
+
);
|
|
294
|
+
const event = genEvent({ kind: 1, content: "hello world" }, sk);
|
|
242
295
|
|
|
243
296
|
const result = await policy.call(event);
|
|
244
297
|
|
|
245
|
-
|
|
298
|
+
deepStrictEqual(result, ["OK", event.id, true, ""]);
|
|
246
299
|
});
|
package/DomainPolicy.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NIP05, NSchema as n } from '@nostrify/nostrify';
|
|
2
|
-
import { NPolicy, NProfilePointer, NStore } from '@nostrify/types';
|
|
2
|
+
import type { NostrEvent, NPolicy, NProfilePointer, NStore } from '@nostrify/types';
|
|
3
3
|
|
|
4
|
-
import { AuthorPolicy } from './AuthorPolicy.
|
|
4
|
+
import { AuthorPolicy } from './AuthorPolicy.ts';
|
|
5
5
|
|
|
6
6
|
/** Options for `DomainPolicy`. */
|
|
7
7
|
interface DomainPolicyOpts {
|
|
@@ -17,7 +17,7 @@ interface DomainPolicyOpts {
|
|
|
17
17
|
export class DomainPolicy extends AuthorPolicy implements NPolicy {
|
|
18
18
|
constructor(store: NStore, opts: DomainPolicyOpts = {}) {
|
|
19
19
|
super(store, {
|
|
20
|
-
async call(event, signal) {
|
|
20
|
+
async call(event: NostrEvent, signal: AbortSignal) {
|
|
21
21
|
const { blacklist = [], whitelist, lookup = DomainPolicy.lookup } = opts;
|
|
22
22
|
|
|
23
23
|
const metadata = n.json().pipe(n.metadata()).safeParse(event.content);
|
package/FiltersPolicy.test.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { finalizeEvent, generateSecretKey } from "nostr-tools";
|
|
3
4
|
|
|
4
|
-
import { FiltersPolicy } from
|
|
5
|
+
import { FiltersPolicy } from "./FiltersPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("FiltersPolicy", async () => {
|
|
7
8
|
const event = finalizeEvent(
|
|
8
|
-
{ kind: 1, content:
|
|
9
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
9
10
|
generateSecretKey(),
|
|
10
11
|
);
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
deepStrictEqual(
|
|
14
|
+
(await new FiltersPolicy([{ kinds: [1] }]).call(event))[2],
|
|
15
|
+
true,
|
|
16
|
+
);
|
|
17
|
+
deepStrictEqual(
|
|
18
|
+
(await new FiltersPolicy([{ kinds: [1], authors: [] }]).call(event))[2],
|
|
19
|
+
false,
|
|
20
|
+
);
|
|
14
21
|
});
|
package/FiltersPolicy.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { matchFilters } from 'nostr-tools';
|
|
2
2
|
|
|
3
|
-
import { NostrEvent, NostrFilter, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
3
|
+
import type { NostrEvent, NostrFilter, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Reject events which don't match the filters.
|
|
@@ -14,7 +14,10 @@ import { NostrEvent, NostrFilter, NostrRelayOK, NPolicy } from '@nostrify/types'
|
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
export class FiltersPolicy implements NPolicy {
|
|
17
|
-
|
|
17
|
+
private filters: NostrFilter[];
|
|
18
|
+
constructor(filters: NostrFilter[]) {
|
|
19
|
+
this.filters = filters;
|
|
20
|
+
}
|
|
18
21
|
|
|
19
22
|
// deno-lint-ignore require-await
|
|
20
23
|
async call(event: NostrEvent): Promise<NostrRelayOK> {
|
package/HashtagPolicy.test.ts
CHANGED
|
@@ -1,34 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { finalizeEvent, generateSecretKey } from "nostr-tools";
|
|
3
4
|
|
|
4
|
-
import { HashtagPolicy } from
|
|
5
|
+
import { HashtagPolicy } from "./HashtagPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
const hashtags = [
|
|
7
|
+
await test("HashtagPolicy", async () => {
|
|
8
|
+
const hashtags = ["nsfw"];
|
|
8
9
|
|
|
9
10
|
const event1 = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
14
15
|
const event2 = finalizeEvent(
|
|
15
|
-
{
|
|
16
|
+
{
|
|
17
|
+
kind: 1,
|
|
18
|
+
content: "",
|
|
19
|
+
tags: [["t", "nsfw"], ["t", "other"]],
|
|
20
|
+
created_at: 0,
|
|
21
|
+
},
|
|
16
22
|
generateSecretKey(),
|
|
17
23
|
);
|
|
18
24
|
|
|
19
25
|
const event3 = finalizeEvent(
|
|
20
|
-
{ kind: 1, content:
|
|
26
|
+
{ kind: 1, content: "nsfw", tags: [], created_at: 0 },
|
|
21
27
|
generateSecretKey(),
|
|
22
28
|
);
|
|
23
29
|
|
|
24
30
|
const event4 = finalizeEvent(
|
|
25
|
-
{
|
|
31
|
+
{
|
|
32
|
+
kind: 1,
|
|
33
|
+
content: "",
|
|
34
|
+
tags: [["p", "nsfw"], ["t", "other"]],
|
|
35
|
+
created_at: 0,
|
|
36
|
+
},
|
|
26
37
|
generateSecretKey(),
|
|
27
38
|
);
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
deepStrictEqual((await new HashtagPolicy(hashtags).call(event1))[2], true);
|
|
41
|
+
deepStrictEqual((await new HashtagPolicy(hashtags).call(event2))[2], false);
|
|
42
|
+
deepStrictEqual((await new HashtagPolicy([]).call(event2))[2], true);
|
|
43
|
+
deepStrictEqual((await new HashtagPolicy(hashtags).call(event3))[2], true);
|
|
44
|
+
deepStrictEqual((await new HashtagPolicy(hashtags).call(event4))[2], true);
|
|
34
45
|
});
|
package/HashtagPolicy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Reject events containing any of the banned hashtags.
|
|
@@ -10,7 +10,10 @@ import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
12
|
export class HashtagPolicy implements NPolicy {
|
|
13
|
-
|
|
13
|
+
private hashtags: string[];
|
|
14
|
+
constructor(hashtags: string[]) {
|
|
15
|
+
this.hashtags = hashtags;
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
// deno-lint-ignore require-await
|
|
16
19
|
async call({ id, tags }: NostrEvent): Promise<NostrRelayOK> {
|
package/HellthreadPolicy.test.ts
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { finalizeEvent, generateSecretKey } from "nostr-tools";
|
|
3
4
|
|
|
4
|
-
import { HellthreadPolicy } from
|
|
5
|
+
import { HellthreadPolicy } from "./HellthreadPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("HellthreadPolicy", async () => {
|
|
7
8
|
const policy = new HellthreadPolicy({ limit: 1 });
|
|
8
9
|
|
|
9
10
|
const okEvent = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
14
15
|
const badEvent = finalizeEvent({
|
|
15
16
|
kind: 1,
|
|
16
|
-
content:
|
|
17
|
-
tags: [[
|
|
17
|
+
content: "",
|
|
18
|
+
tags: [["p"], ["p"], ["p"]],
|
|
18
19
|
created_at: 0,
|
|
19
20
|
}, generateSecretKey());
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
deepStrictEqual((await policy.call(okEvent))[2], true);
|
|
23
|
+
deepStrictEqual((await policy.call(badEvent))[2], false);
|
|
23
24
|
});
|
package/HellthreadPolicy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
2
2
|
|
|
3
3
|
/** Policy options for `HellthreadPolicy`. */
|
|
4
4
|
interface HellthreadPolicyOpts {
|
|
@@ -8,14 +8,17 @@ interface HellthreadPolicyOpts {
|
|
|
8
8
|
|
|
9
9
|
/** Basic policy to demonstrate how policies work. Accepts all events. */
|
|
10
10
|
export class HellthreadPolicy implements NPolicy {
|
|
11
|
-
|
|
11
|
+
private opts: HellthreadPolicyOpts;
|
|
12
|
+
constructor(opts: HellthreadPolicyOpts = {}) {
|
|
13
|
+
this.opts = opts;
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
// deno-lint-ignore require-await
|
|
14
17
|
async call({ id, kind, tags }: NostrEvent): Promise<NostrRelayOK> {
|
|
15
18
|
const { limit = 100 } = this.opts;
|
|
16
19
|
|
|
17
20
|
if (kind === 1) {
|
|
18
|
-
const p = tags.filter((tag) => tag[0] === 'p');
|
|
21
|
+
const p = tags.filter((tag: string[]) => tag[0] === 'p');
|
|
19
22
|
|
|
20
23
|
if (p.length > limit) {
|
|
21
24
|
return ['OK', id, false, `blocked: rejected due to ${p.length} "p" tags (${limit} is the limit).`];
|
package/InvertPolicy.test.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { finalizeEvent, generateSecretKey } from "nostr-tools";
|
|
3
4
|
|
|
4
|
-
import { InvertPolicy } from
|
|
5
|
-
import { NoOpPolicy } from
|
|
5
|
+
import { InvertPolicy } from "./InvertPolicy.ts";
|
|
6
|
+
import { NoOpPolicy } from "./NoOpPolicy.ts";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
const policy = new InvertPolicy(new NoOpPolicy(),
|
|
8
|
+
await test("InvertPolicy", async () => {
|
|
9
|
+
const policy = new InvertPolicy(new NoOpPolicy(), "blocked: inverted");
|
|
9
10
|
|
|
10
11
|
const event = finalizeEvent(
|
|
11
|
-
{ kind: 1, content:
|
|
12
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
12
13
|
generateSecretKey(),
|
|
13
14
|
);
|
|
14
15
|
|
|
15
16
|
const [_, _eventId, ok, reason] = await policy.call(event);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
deepStrictEqual(ok, false);
|
|
19
|
+
deepStrictEqual(reason, "blocked: inverted");
|
|
19
20
|
});
|
package/InvertPolicy.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
2
2
|
|
|
3
3
|
/** Rejects if the policy passes, passes if the policy rejects. */
|
|
4
4
|
export class InvertPolicy implements NPolicy {
|
|
5
|
-
|
|
5
|
+
private policy: NPolicy;
|
|
6
|
+
private reason: string;
|
|
7
|
+
|
|
8
|
+
constructor(policy: NPolicy, reason: string) {
|
|
9
|
+
this.policy = policy;
|
|
10
|
+
this.reason = reason;
|
|
11
|
+
}
|
|
6
12
|
|
|
7
13
|
async call(event: NostrEvent): Promise<NostrRelayOK> {
|
|
8
14
|
const result = await this.policy.call(event);
|