@nostrify/policies 0.36.4 → 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 +18 -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 +10 -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/KeywordPolicy.test.ts
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
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 { KeywordPolicy } from
|
|
5
|
+
import { KeywordPolicy } from "./KeywordPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
const words = [
|
|
7
|
+
await test("KeywordPolicy", async () => {
|
|
8
|
+
const words = ["https://t.me/spam", "hello world"];
|
|
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: "🔥🔥🔥 https://t.me/spam 我想死",
|
|
19
|
+
tags: [],
|
|
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: "hElLo wOrLd!", tags: [], created_at: 0 },
|
|
21
27
|
generateSecretKey(),
|
|
22
28
|
);
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
deepStrictEqual((await new KeywordPolicy(words).call(event1))[2], true);
|
|
31
|
+
deepStrictEqual((await new KeywordPolicy(words).call(event2))[2], false);
|
|
32
|
+
deepStrictEqual((await new KeywordPolicy([]).call(event2))[2], true);
|
|
33
|
+
deepStrictEqual((await new KeywordPolicy(words).call(event3))[2], false);
|
|
28
34
|
});
|
package/KeywordPolicy.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 strings in its content.
|
|
@@ -10,7 +10,10 @@ import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
12
|
export class KeywordPolicy implements NPolicy {
|
|
13
|
-
|
|
13
|
+
private words: Iterable<string>;
|
|
14
|
+
constructor(words: Iterable<string>) {
|
|
15
|
+
this.words = words;
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
// deno-lint-ignore require-await
|
|
16
19
|
async call({ id, content }: NostrEvent): Promise<NostrRelayOK> {
|
package/NoOpPolicy.test.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
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 { NoOpPolicy } from
|
|
5
|
+
import { NoOpPolicy } from "./NoOpPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("NoOpPolicy", async () => {
|
|
7
8
|
const policy = new NoOpPolicy();
|
|
8
9
|
|
|
9
10
|
const event = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
14
15
|
const [_, eventId, ok] = await policy.call(event);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
deepStrictEqual(eventId, event.id);
|
|
18
|
+
deepStrictEqual(ok, true);
|
|
18
19
|
});
|
package/NoOpPolicy.ts
CHANGED
package/OpenAIPolicy.test.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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 { OpenAIPolicy } from
|
|
5
|
+
import { OpenAIPolicy } from "./OpenAIPolicy.ts";
|
|
5
6
|
|
|
6
7
|
const timeout = 50;
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
await test("rejects flagged events", async () => {
|
|
9
10
|
const event = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "I want to kill them.", tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
@@ -18,14 +19,20 @@ Deno.test('rejects flagged events', async () => {
|
|
|
18
19
|
),
|
|
19
20
|
);
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
deepStrictEqual(
|
|
23
|
+
(await new OpenAIPolicy({ apiKey: "", fetch }).call(
|
|
24
|
+
event,
|
|
25
|
+
AbortSignal.timeout(timeout),
|
|
26
|
+
))[2],
|
|
27
|
+
false,
|
|
28
|
+
);
|
|
22
29
|
|
|
23
30
|
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
24
31
|
});
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
await test("accepts unflagged events", async () => {
|
|
27
34
|
const event = finalizeEvent(
|
|
28
|
-
{ kind: 1, content:
|
|
35
|
+
{ kind: 1, content: "I want to love them.", tags: [], created_at: 0 },
|
|
29
36
|
generateSecretKey(),
|
|
30
37
|
);
|
|
31
38
|
|
|
@@ -36,7 +43,13 @@ Deno.test('accepts unflagged events', async () => {
|
|
|
36
43
|
),
|
|
37
44
|
);
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
deepStrictEqual(
|
|
47
|
+
(await new OpenAIPolicy({ apiKey: "", fetch }).call(
|
|
48
|
+
event,
|
|
49
|
+
AbortSignal.timeout(timeout),
|
|
50
|
+
))[2],
|
|
51
|
+
false,
|
|
52
|
+
);
|
|
40
53
|
|
|
41
54
|
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
42
55
|
});
|
package/OpenAIPolicy.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
|
* OpenAI moderation result.
|
|
@@ -75,7 +75,10 @@ interface OpenAIPolicyOpts {
|
|
|
75
75
|
* ```
|
|
76
76
|
*/
|
|
77
77
|
export class OpenAIPolicy implements NPolicy {
|
|
78
|
-
|
|
78
|
+
private opts: OpenAIPolicyOpts;
|
|
79
|
+
constructor(opts: OpenAIPolicyOpts) {
|
|
80
|
+
this.opts = opts;
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
async call(event: NostrEvent, signal?: AbortSignal): Promise<NostrRelayOK> {
|
|
81
84
|
const {
|
package/PipePolicy.test.ts
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
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 { NoOpPolicy } from
|
|
5
|
-
import { PipePolicy } from
|
|
6
|
-
import { ReadOnlyPolicy } from
|
|
5
|
+
import { NoOpPolicy } from "./NoOpPolicy.ts";
|
|
6
|
+
import { PipePolicy } from "./PipePolicy.ts";
|
|
7
|
+
import { ReadOnlyPolicy } from "./ReadOnlyPolicy.ts";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
await test("passes events through multiple policies", async () => {
|
|
9
10
|
const policy = new PipePolicy([
|
|
10
11
|
new NoOpPolicy(),
|
|
11
12
|
new ReadOnlyPolicy(),
|
|
12
13
|
]);
|
|
13
14
|
|
|
14
15
|
const event = finalizeEvent(
|
|
15
|
-
{ kind: 1, content:
|
|
16
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
16
17
|
generateSecretKey(),
|
|
17
18
|
);
|
|
18
19
|
|
|
19
20
|
const [_, _eventId, ok, reason] = await policy.call(event);
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
deepStrictEqual(ok, false);
|
|
23
|
+
deepStrictEqual(reason, "blocked: the relay is read-only");
|
|
23
24
|
});
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
await test("short-circuits on the first reject", async () => {
|
|
26
27
|
const policy = new PipePolicy([
|
|
27
28
|
new ReadOnlyPolicy(),
|
|
28
29
|
new NoOpPolicy(),
|
|
29
30
|
]);
|
|
30
31
|
|
|
31
32
|
const event = finalizeEvent(
|
|
32
|
-
{ kind: 1, content:
|
|
33
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
33
34
|
generateSecretKey(),
|
|
34
35
|
);
|
|
35
36
|
|
|
36
37
|
const [_, _eventId, ok, reason] = await policy.call(event);
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
deepStrictEqual(ok, false);
|
|
40
|
+
deepStrictEqual(reason, "blocked: the relay is read-only");
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
await test("accepts when all policies accept", async () => {
|
|
43
44
|
const policy = new PipePolicy([
|
|
44
45
|
new NoOpPolicy(),
|
|
45
46
|
new NoOpPolicy(),
|
|
@@ -47,12 +48,12 @@ Deno.test('accepts when all policies accept', async () => {
|
|
|
47
48
|
]);
|
|
48
49
|
|
|
49
50
|
const event = finalizeEvent(
|
|
50
|
-
{ kind: 1, content:
|
|
51
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
51
52
|
generateSecretKey(),
|
|
52
53
|
);
|
|
53
54
|
|
|
54
55
|
const [_, _eventId, ok, reason] = await policy.call(event);
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
deepStrictEqual(ok, true);
|
|
58
|
+
deepStrictEqual(reason, "");
|
|
58
59
|
});
|
package/PipePolicy.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
|
* Processes events through multiple policies.
|
|
@@ -20,7 +20,10 @@ import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export class PipePolicy implements NPolicy {
|
|
23
|
-
|
|
23
|
+
private policies: NPolicy[] = [];
|
|
24
|
+
constructor(policies: NPolicy[]) {
|
|
25
|
+
this.policies = policies;
|
|
26
|
+
}
|
|
24
27
|
|
|
25
28
|
async call(event: NostrEvent, signal?: AbortSignal): Promise<NostrRelayOK> {
|
|
26
29
|
for (const policy of this.policies) {
|
package/PowPolicy.test.ts
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
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 { PowPolicy } from
|
|
5
|
+
import { PowPolicy } from "./PowPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("blocks events without a nonce", 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
|
+
deepStrictEqual((await new PowPolicy().call(event))[2], false);
|
|
13
14
|
});
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
await test("accepts event with sufficient POW", async () => {
|
|
16
17
|
const event = {
|
|
17
|
-
id:
|
|
18
|
-
tags: [[
|
|
18
|
+
id: "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358",
|
|
19
|
+
tags: [["nonce", "776797", "20"]],
|
|
19
20
|
kind: 1,
|
|
20
|
-
content:
|
|
21
|
-
pubkey:
|
|
21
|
+
content: "",
|
|
22
|
+
pubkey: "",
|
|
22
23
|
created_at: 0,
|
|
23
|
-
sig:
|
|
24
|
+
sig: "",
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
deepStrictEqual((await new PowPolicy().call(event))[2], true);
|
|
27
28
|
});
|
package/PowPolicy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NostrEvent, NostrRelayInfo, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent, NostrRelayInfo, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
2
2
|
import { nip13 } from 'nostr-tools';
|
|
3
3
|
|
|
4
4
|
/** Policy options for `PowPolicy`. */
|
|
@@ -15,14 +15,17 @@ interface PowPolicyOpts {
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
export class PowPolicy implements NPolicy {
|
|
18
|
-
|
|
18
|
+
private opts: PowPolicyOpts;
|
|
19
|
+
constructor(opts: PowPolicyOpts = {}) {
|
|
20
|
+
this.opts = opts;
|
|
21
|
+
}
|
|
19
22
|
|
|
20
23
|
// deno-lint-ignore require-await
|
|
21
24
|
async call({ id, tags }: NostrEvent): Promise<NostrRelayOK> {
|
|
22
25
|
const { difficulty = 1 } = this.opts;
|
|
23
26
|
|
|
24
27
|
const pow = nip13.getPow(id);
|
|
25
|
-
const nonce = tags.find(([name]) => name === 'nonce');
|
|
28
|
+
const nonce = tags.find(([name]: string[]) => name === 'nonce');
|
|
26
29
|
|
|
27
30
|
if (pow >= difficulty && nonce && Number(nonce[2]) >= difficulty) {
|
|
28
31
|
return ['OK', id, true, ''];
|
package/PubkeyBanPolicy.test.ts
CHANGED
|
@@ -1,17 +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 { PubkeyBanPolicy } from
|
|
5
|
+
import { PubkeyBanPolicy } from "./PubkeyBanPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("PubkeyBanPolicy", async () => {
|
|
7
8
|
const [event1, event2, event3] = new Array(3).fill(0).map(() => {
|
|
8
9
|
return finalizeEvent(
|
|
9
|
-
{ kind: 1, content:
|
|
10
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
10
11
|
generateSecretKey(),
|
|
11
12
|
);
|
|
12
13
|
});
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
deepStrictEqual((await new PubkeyBanPolicy([]).call(event1))[2], true);
|
|
16
|
+
deepStrictEqual(
|
|
17
|
+
(await new PubkeyBanPolicy([event2.pubkey, event1.pubkey]).call(event3))[2],
|
|
18
|
+
true,
|
|
19
|
+
);
|
|
20
|
+
deepStrictEqual(
|
|
21
|
+
(await new PubkeyBanPolicy([event2.pubkey, event1.pubkey]).call(event2))[2],
|
|
22
|
+
false,
|
|
23
|
+
);
|
|
17
24
|
});
|
package/PubkeyBanPolicy.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
|
* Ban events from individual pubkeys.
|
|
@@ -9,7 +9,10 @@ import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
export class PubkeyBanPolicy implements NPolicy {
|
|
12
|
-
|
|
12
|
+
private pubkeys: Iterable<string>;
|
|
13
|
+
constructor(pubkeys: Iterable<string>) {
|
|
14
|
+
this.pubkeys = pubkeys;
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
// deno-lint-ignore require-await
|
|
15
18
|
async call({ id, pubkey }: NostrEvent): Promise<NostrRelayOK> {
|
package/ReadOnlyPolicy.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 { ReadOnlyPolicy } from
|
|
5
|
+
import { ReadOnlyPolicy } from "./ReadOnlyPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("ReadOnlyPolicy", async () => {
|
|
7
8
|
const policy = new ReadOnlyPolicy();
|
|
8
9
|
|
|
9
10
|
const event = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "", tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
14
15
|
const [_, eventId, ok, reason] = await policy.call(event);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
deepStrictEqual(eventId, event.id);
|
|
18
|
+
deepStrictEqual(reason, "blocked: the relay is read-only");
|
|
19
|
+
deepStrictEqual(ok, false);
|
|
19
20
|
});
|
package/ReadOnlyPolicy.ts
CHANGED
package/RegexPolicy.test.ts
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
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 { RegexPolicy } from
|
|
5
|
+
import { RegexPolicy } from "./RegexPolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("RegexPolicy", async () => {
|
|
7
8
|
const event = finalizeEvent(
|
|
8
|
-
{
|
|
9
|
+
{
|
|
10
|
+
kind: 1,
|
|
11
|
+
content: "🔥🔥🔥 https://t.me/spam 我想死",
|
|
12
|
+
tags: [],
|
|
13
|
+
created_at: 0,
|
|
14
|
+
},
|
|
9
15
|
generateSecretKey(),
|
|
10
16
|
);
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
deepStrictEqual(
|
|
19
|
+
(await new RegexPolicy(/https:\/\/t\.me\/\w+/i).call(event))[2],
|
|
20
|
+
false,
|
|
21
|
+
);
|
|
22
|
+
deepStrictEqual((await new RegexPolicy(/🔥{1,3}/).call(event))[2], false);
|
|
23
|
+
deepStrictEqual((await new RegexPolicy(/🔥{4}/).call(event))[2], true);
|
|
24
|
+
deepStrictEqual((await new RegexPolicy(/🔥$/).call(event))[2], true);
|
|
25
|
+
deepStrictEqual((await new RegexPolicy(/^🔥/).call(event))[2], false);
|
|
17
26
|
});
|
package/RegexPolicy.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 whose content matches the regex.
|
|
@@ -9,7 +9,10 @@ import { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
export class RegexPolicy implements NPolicy {
|
|
12
|
-
|
|
12
|
+
private regex: RegExp;
|
|
13
|
+
constructor(regex: RegExp) {
|
|
14
|
+
this.regex = regex;
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
// deno-lint-ignore require-await
|
|
15
18
|
async call({ id, content }: NostrEvent): Promise<NostrRelayOK> {
|
package/ReplyBotPolicy.test.ts
CHANGED
|
@@ -1,50 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { genEvent, MockRelay } from "@nostrify/nostrify/test";
|
|
4
|
+
import { generateSecretKey, getPublicKey } from "nostr-tools";
|
|
4
5
|
|
|
5
|
-
import { ReplyBotPolicy } from
|
|
6
|
+
import { ReplyBotPolicy } from "./ReplyBotPolicy.ts";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
await test("ReplyBotPolicy blocks replies within the same second", async () => {
|
|
8
9
|
const store = new MockRelay();
|
|
9
|
-
|
|
10
|
+
try {
|
|
11
|
+
const policy = new ReplyBotPolicy({ store });
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const event = genEvent({ kind: 1, created_at: 0 });
|
|
14
|
+
const reply = genEvent({ kind: 1, created_at: 1, tags: [["e", event.id]] });
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
await store.event(event);
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
const [, , ok] = await policy.call(reply);
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
deepStrictEqual(ok, false);
|
|
21
|
+
} finally {
|
|
22
|
+
await store.close();
|
|
23
|
+
}
|
|
19
24
|
});
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
await test("ReplyBotPolicy allows replies after 1 second", async () => {
|
|
22
27
|
const store = new MockRelay();
|
|
23
|
-
|
|
28
|
+
try {
|
|
29
|
+
const policy = new ReplyBotPolicy({ store });
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
const event = genEvent({ kind: 1, created_at: 0 });
|
|
32
|
+
const reply = genEvent({ kind: 1, created_at: 2, tags: [["e", event.id]] });
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
await store.event(event);
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
const [, , ok] = await policy.call(reply);
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
deepStrictEqual(ok, true);
|
|
39
|
+
} finally {
|
|
40
|
+
await store.close();
|
|
41
|
+
}
|
|
33
42
|
});
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
await test("ReplyBotPolicy allows replies within the same second from users who are tagged", async () => {
|
|
36
45
|
const store = new MockRelay();
|
|
37
|
-
|
|
46
|
+
try {
|
|
47
|
+
const policy = new ReplyBotPolicy({ store });
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const sk = generateSecretKey();
|
|
50
|
+
const pubkey = getPublicKey(sk);
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
const event = genEvent({ kind: 1, created_at: 0, tags: [["p", pubkey]] });
|
|
53
|
+
const reply = genEvent(
|
|
54
|
+
{ kind: 1, created_at: 1, tags: [["e", event.id]] },
|
|
55
|
+
sk,
|
|
56
|
+
);
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
await store.event(event);
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
const [, , ok] = await policy.call(reply);
|
|
48
61
|
|
|
49
|
-
|
|
62
|
+
deepStrictEqual(ok, true);
|
|
63
|
+
} finally {
|
|
64
|
+
await store.close();
|
|
65
|
+
}
|
|
50
66
|
});
|
package/ReplyBotPolicy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
|
|
1
|
+
import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
|
|
2
2
|
|
|
3
3
|
/** Options for the ReplyBotPolicy. */
|
|
4
4
|
export interface ReplyBotPolicyOpts {
|
|
@@ -12,7 +12,10 @@ export interface ReplyBotPolicyOpts {
|
|
|
12
12
|
|
|
13
13
|
/** Block events that reply too quickly to another event. */
|
|
14
14
|
export class ReplyBotPolicy implements NPolicy {
|
|
15
|
-
|
|
15
|
+
private opts: ReplyBotPolicyOpts;
|
|
16
|
+
constructor(opts: ReplyBotPolicyOpts) {
|
|
17
|
+
this.opts = opts;
|
|
18
|
+
}
|
|
16
19
|
|
|
17
20
|
async call(event: NostrEvent, signal?: AbortSignal): Promise<NostrRelayOK> {
|
|
18
21
|
const { store, threshold = 1, kinds = [1] } = this.opts;
|
|
@@ -25,7 +28,7 @@ export class ReplyBotPolicy implements NPolicy {
|
|
|
25
28
|
|
|
26
29
|
if (prevEvent) {
|
|
27
30
|
const diff = event.created_at - prevEvent.created_at;
|
|
28
|
-
const pTag = prevEvent.tags.find(([name, value]) => name === 'p' && value === event.pubkey);
|
|
31
|
+
const pTag = prevEvent.tags.find(([name, value]: string[]) => name === 'p' && value === event.pubkey);
|
|
29
32
|
|
|
30
33
|
if (diff <= threshold && !pTag) {
|
|
31
34
|
return ['OK', event.id, false, 'rate-limited: replied too quickly'];
|
package/SizePolicy.test.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
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 { SizePolicy } from
|
|
5
|
+
import { SizePolicy } from "./SizePolicy.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
await test("SizePolicy", async () => {
|
|
7
8
|
const policy = new SizePolicy();
|
|
8
9
|
|
|
9
10
|
const event = finalizeEvent(
|
|
10
|
-
{ kind: 1, content:
|
|
11
|
+
{ kind: 1, content: "yolo".repeat(100), tags: [], created_at: 0 },
|
|
11
12
|
generateSecretKey(),
|
|
12
13
|
);
|
|
13
14
|
|
|
14
15
|
const bigEvent = finalizeEvent(
|
|
15
|
-
{ kind: 1, content:
|
|
16
|
+
{ kind: 1, content: "yolo".repeat(2500), tags: [], created_at: 0 },
|
|
16
17
|
generateSecretKey(),
|
|
17
18
|
);
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
deepStrictEqual((await policy.call(event))[2], true);
|
|
21
|
+
deepStrictEqual((await policy.call(bigEvent))[2], false);
|
|
21
22
|
});
|