@nostrify/policies 0.36.7 → 0.36.8

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.
Files changed (88) hide show
  1. package/.turbo/turbo-build.log +9 -17
  2. package/CHANGELOG.md +9 -0
  3. package/dist/AntiDuplicationPolicy.d.ts +43 -0
  4. package/dist/AntiDuplicationPolicy.d.ts.map +1 -0
  5. package/dist/AntiDuplicationPolicy.js +44 -0
  6. package/dist/AntiDuplicationPolicy.ts +82 -0
  7. package/dist/AnyPolicy.d.ts +8 -0
  8. package/dist/AnyPolicy.d.ts.map +1 -0
  9. package/dist/AnyPolicy.js +20 -0
  10. package/dist/AnyPolicy.ts +24 -0
  11. package/dist/AuthorPolicy.d.ts +9 -0
  12. package/dist/AuthorPolicy.d.ts.map +1 -0
  13. package/dist/AuthorPolicy.js +22 -0
  14. package/dist/AuthorPolicy.ts +29 -0
  15. package/dist/DomainPolicy.d.ts +21 -0
  16. package/dist/DomainPolicy.d.ts.map +1 -0
  17. package/dist/DomainPolicy.js +62 -0
  18. package/dist/DomainPolicy.ts +96 -0
  19. package/dist/FiltersPolicy.d.ts +18 -0
  20. package/dist/FiltersPolicy.d.ts.map +1 -0
  21. package/dist/FiltersPolicy.js +17 -0
  22. package/dist/FiltersPolicy.ts +30 -0
  23. package/dist/HashtagPolicy.d.ts +16 -0
  24. package/dist/HashtagPolicy.d.ts.map +1 -0
  25. package/dist/HashtagPolicy.js +18 -0
  26. package/dist/HashtagPolicy.ts +28 -0
  27. package/dist/HellthreadPolicy.d.ts +14 -0
  28. package/dist/HellthreadPolicy.d.ts.map +1 -0
  29. package/dist/HellthreadPolicy.js +20 -0
  30. package/dist/HellthreadPolicy.ts +30 -0
  31. package/dist/InvertPolicy.d.ts +9 -0
  32. package/dist/InvertPolicy.d.ts.map +1 -0
  33. package/dist/InvertPolicy.js +20 -0
  34. package/dist/InvertPolicy.ts +23 -0
  35. package/dist/KeywordPolicy.d.ts +16 -0
  36. package/dist/KeywordPolicy.d.ts.map +1 -0
  37. package/dist/KeywordPolicy.js +18 -0
  38. package/dist/KeywordPolicy.ts +28 -0
  39. package/dist/NoOpPolicy.d.ts +6 -0
  40. package/dist/NoOpPolicy.d.ts.map +1 -0
  41. package/dist/NoOpPolicy.js +9 -0
  42. package/dist/NoOpPolicy.ts +9 -0
  43. package/dist/OpenAIPolicy.d.ts +80 -0
  44. package/dist/OpenAIPolicy.d.ts.map +1 -0
  45. package/dist/OpenAIPolicy.js +38 -0
  46. package/dist/OpenAIPolicy.ts +116 -0
  47. package/dist/PipePolicy.d.ts +26 -0
  48. package/dist/PipePolicy.d.ts.map +1 -0
  49. package/dist/PipePolicy.js +18 -0
  50. package/dist/PipePolicy.ts +39 -0
  51. package/dist/PowPolicy.d.ts +21 -0
  52. package/dist/PowPolicy.d.ts.map +1 -0
  53. package/dist/PowPolicy.js +27 -0
  54. package/dist/PowPolicy.ts +44 -0
  55. package/dist/PubkeyBanPolicy.d.ts +15 -0
  56. package/dist/PubkeyBanPolicy.d.ts.map +1 -0
  57. package/dist/PubkeyBanPolicy.js +18 -0
  58. package/dist/PubkeyBanPolicy.ts +27 -0
  59. package/dist/ReadOnlyPolicy.d.ts +6 -0
  60. package/dist/ReadOnlyPolicy.d.ts.map +1 -0
  61. package/dist/ReadOnlyPolicy.js +9 -0
  62. package/dist/ReadOnlyPolicy.ts +9 -0
  63. package/dist/RegexPolicy.d.ts +15 -0
  64. package/dist/RegexPolicy.d.ts.map +1 -0
  65. package/dist/RegexPolicy.js +16 -0
  66. package/dist/RegexPolicy.ts +25 -0
  67. package/dist/ReplyBotPolicy.d.ts +25 -0
  68. package/dist/ReplyBotPolicy.d.ts.map +1 -0
  69. package/dist/ReplyBotPolicy.js +42 -0
  70. package/dist/ReplyBotPolicy.ts +62 -0
  71. package/dist/SizePolicy.d.ts +23 -0
  72. package/dist/SizePolicy.d.ts.map +1 -0
  73. package/dist/SizePolicy.js +19 -0
  74. package/dist/SizePolicy.ts +39 -0
  75. package/dist/WhitelistPolicy.d.ts +16 -0
  76. package/dist/WhitelistPolicy.d.ts.map +1 -0
  77. package/dist/WhitelistPolicy.js +25 -0
  78. package/dist/WhitelistPolicy.ts +36 -0
  79. package/dist/WoTPolicy.d.ts +26 -0
  80. package/dist/WoTPolicy.d.ts.map +1 -0
  81. package/dist/WoTPolicy.js +39 -0
  82. package/dist/WoTPolicy.ts +64 -0
  83. package/dist/mod.d.ts +21 -0
  84. package/dist/mod.d.ts.map +1 -0
  85. package/dist/mod.js +42 -0
  86. package/dist/mod.ts +20 -0
  87. package/dist/tsconfig.tsbuildinfo +1 -0
  88. package/package.json +3 -3
@@ -0,0 +1,44 @@
1
+ import type { NostrEvent, NostrRelayInfo, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ import { nip13 } from 'nostr-tools';
3
+
4
+ /** Policy options for `PowPolicy`. */
5
+ interface PowPolicyOpts {
6
+ /** Events will be rejected if their `id` does not contain at least this many leading 0 bits. Default: `1` */
7
+ difficulty?: number;
8
+ }
9
+
10
+ /**
11
+ * Reject events which don't meet Proof-of-Work ([NIP-13](https://github.com/nostr-protocol/nips/blob/master/13.md)) criteria.
12
+ *
13
+ * ```ts
14
+ * new PowPolicy({ difficulty: 20 });
15
+ * ```
16
+ */
17
+ export class PowPolicy implements NPolicy {
18
+ private opts: PowPolicyOpts;
19
+ constructor(opts: PowPolicyOpts = {}) {
20
+ this.opts = opts;
21
+ }
22
+
23
+ // deno-lint-ignore require-await
24
+ async call({ id, tags }: NostrEvent): Promise<NostrRelayOK> {
25
+ const { difficulty = 1 } = this.opts;
26
+
27
+ const pow = nip13.getPow(id);
28
+ const nonce = tags.find(([name]: string[]) => name === 'nonce');
29
+
30
+ if (pow >= difficulty && nonce && Number(nonce[2]) >= difficulty) {
31
+ return ['OK', id, true, ''];
32
+ }
33
+
34
+ return ['OK', id, false, `pow: insufficient proof-of-work (difficulty ${difficulty})`];
35
+ }
36
+
37
+ get info(): NostrRelayInfo {
38
+ return {
39
+ limitation: {
40
+ min_pow_difficulty: this.opts.difficulty,
41
+ },
42
+ };
43
+ }
44
+ }
@@ -0,0 +1,15 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ /**
3
+ * Ban events from individual pubkeys.
4
+ *
5
+ * ```ts
6
+ * // Ban a specific pubkey.
7
+ * new PubkeyBanPolicy(['e810fafa1e89cdf80cced8e013938e87e21b699b24c8570537be92aec4b12c18']);
8
+ * ```
9
+ */
10
+ export declare class PubkeyBanPolicy implements NPolicy {
11
+ private pubkeys;
12
+ constructor(pubkeys: Iterable<string>);
13
+ call({ id, pubkey }: NostrEvent): Promise<NostrRelayOK>;
14
+ }
15
+ //# sourceMappingURL=PubkeyBanPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PubkeyBanPolicy.d.ts","sourceRoot":"","sources":["../PubkeyBanPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;;GAOG;AACH,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,OAAO,CAAmB;gBACtB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC;IAK/B,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CAS9D"}
@@ -0,0 +1,18 @@
1
+ class PubkeyBanPolicy {
2
+ pubkeys;
3
+ constructor(pubkeys) {
4
+ this.pubkeys = pubkeys;
5
+ }
6
+ // deno-lint-ignore require-await
7
+ async call({ id, pubkey }) {
8
+ for (const p of this.pubkeys) {
9
+ if (p === pubkey) {
10
+ return ["OK", id, false, "blocked: pubkey is banned"];
11
+ }
12
+ }
13
+ return ["OK", id, true, ""];
14
+ }
15
+ }
16
+ export {
17
+ PubkeyBanPolicy
18
+ };
@@ -0,0 +1,27 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+
3
+ /**
4
+ * Ban events from individual pubkeys.
5
+ *
6
+ * ```ts
7
+ * // Ban a specific pubkey.
8
+ * new PubkeyBanPolicy(['e810fafa1e89cdf80cced8e013938e87e21b699b24c8570537be92aec4b12c18']);
9
+ * ```
10
+ */
11
+ export class PubkeyBanPolicy implements NPolicy {
12
+ private pubkeys: Iterable<string>;
13
+ constructor(pubkeys: Iterable<string>) {
14
+ this.pubkeys = pubkeys;
15
+ }
16
+
17
+ // deno-lint-ignore require-await
18
+ async call({ id, pubkey }: NostrEvent): Promise<NostrRelayOK> {
19
+ for (const p of this.pubkeys) {
20
+ if (p === pubkey) {
21
+ return ['OK', id, false, 'blocked: pubkey is banned'];
22
+ }
23
+ }
24
+
25
+ return ['OK', id, true, ''];
26
+ }
27
+ }
@@ -0,0 +1,6 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ /** This policy rejects all messages. */
3
+ export declare class ReadOnlyPolicy implements NPolicy {
4
+ call(event: NostrEvent): Promise<NostrRelayOK>;
5
+ }
6
+ //# sourceMappingURL=ReadOnlyPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReadOnlyPolicy.d.ts","sourceRoot":"","sources":["../ReadOnlyPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEzE,wCAAwC;AACxC,qBAAa,cAAe,YAAW,OAAO;IAEtC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CAGrD"}
@@ -0,0 +1,9 @@
1
+ class ReadOnlyPolicy {
2
+ // deno-lint-ignore require-await
3
+ async call(event) {
4
+ return ["OK", event.id, false, "blocked: the relay is read-only"];
5
+ }
6
+ }
7
+ export {
8
+ ReadOnlyPolicy
9
+ };
@@ -0,0 +1,9 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+
3
+ /** This policy rejects all messages. */
4
+ export class ReadOnlyPolicy implements NPolicy {
5
+ // deno-lint-ignore require-await
6
+ async call(event: NostrEvent): Promise<NostrRelayOK> {
7
+ return ['OK', event.id, false, 'blocked: the relay is read-only'];
8
+ }
9
+ }
@@ -0,0 +1,15 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ /**
3
+ * Reject events whose content matches the regex.
4
+ *
5
+ * ```ts
6
+ * // Ban events matching a regex.
7
+ * new RegexPolicy(/(🟠|🔥|😳)ChtaGPT/i);
8
+ * ```
9
+ */
10
+ export declare class RegexPolicy implements NPolicy {
11
+ private regex;
12
+ constructor(regex: RegExp);
13
+ call({ id, content }: NostrEvent): Promise<NostrRelayOK>;
14
+ }
15
+ //# sourceMappingURL=RegexPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegexPolicy.d.ts","sourceRoot":"","sources":["../RegexPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,OAAO;IACzC,OAAO,CAAC,KAAK,CAAS;gBACV,KAAK,EAAE,MAAM;IAKnB,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CAO/D"}
@@ -0,0 +1,16 @@
1
+ class RegexPolicy {
2
+ regex;
3
+ constructor(regex) {
4
+ this.regex = regex;
5
+ }
6
+ // deno-lint-ignore require-await
7
+ async call({ id, content }) {
8
+ if (this.regex.test(content)) {
9
+ return ["OK", id, false, "blocked: text matches a banned expression"];
10
+ }
11
+ return ["OK", id, true, ""];
12
+ }
13
+ }
14
+ export {
15
+ RegexPolicy
16
+ };
@@ -0,0 +1,25 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+
3
+ /**
4
+ * Reject events whose content matches the regex.
5
+ *
6
+ * ```ts
7
+ * // Ban events matching a regex.
8
+ * new RegexPolicy(/(🟠|🔥|😳)ChtaGPT/i);
9
+ * ```
10
+ */
11
+ export class RegexPolicy implements NPolicy {
12
+ private regex: RegExp;
13
+ constructor(regex: RegExp) {
14
+ this.regex = regex;
15
+ }
16
+
17
+ // deno-lint-ignore require-await
18
+ async call({ id, content }: NostrEvent): Promise<NostrRelayOK> {
19
+ if (this.regex.test(content)) {
20
+ return ['OK', id, false, 'blocked: text matches a banned expression'];
21
+ }
22
+
23
+ return ['OK', id, true, ''];
24
+ }
25
+ }
@@ -0,0 +1,25 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
2
+ /** Options for the ReplyBotPolicy. */
3
+ export interface ReplyBotPolicyOpts {
4
+ /** The store to use for fetching events. */
5
+ store: NStore;
6
+ /** The minimum time in seconds between two posts. */
7
+ threshold?: number;
8
+ /** The kinds of events to apply the policy to. */
9
+ kinds?: number[];
10
+ }
11
+ /** Block events that reply too quickly to another event. */
12
+ export declare class ReplyBotPolicy implements NPolicy {
13
+ private opts;
14
+ constructor(opts: ReplyBotPolicyOpts);
15
+ call(event: NostrEvent, signal?: AbortSignal): Promise<NostrRelayOK>;
16
+ /** Tag is a NIP-10 root tag. */
17
+ private static isRootTag;
18
+ /** Tag is a NIP-10 reply tag. */
19
+ private static isReplyTag;
20
+ /** Tag is an "e" tag without a NIP-10 marker. */
21
+ private static isLegacyReplyTag;
22
+ /** Get the "e" tag for the event being replied to, first according to the NIPs then falling back to the legacy way. */
23
+ private static findReplyTag;
24
+ }
25
+ //# sourceMappingURL=ReplyBotPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReplyBotPolicy.d.ts","sourceRoot":"","sources":["../ReplyBotPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEjF,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,4DAA4D;AAC5D,qBAAa,cAAe,YAAW,OAAO;IAC5C,OAAO,CAAC,IAAI,CAAqB;gBACrB,IAAI,EAAE,kBAAkB;IAI9B,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAuB1E,gCAAgC;IAChC,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB,iCAAiC;IACjC,OAAO,CAAC,MAAM,CAAC,UAAU;IAIzB,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B,uHAAuH;IACvH,OAAO,CAAC,MAAM,CAAC,YAAY;CAG5B"}
@@ -0,0 +1,42 @@
1
+ class ReplyBotPolicy {
2
+ opts;
3
+ constructor(opts) {
4
+ this.opts = opts;
5
+ }
6
+ async call(event, signal) {
7
+ const { store, threshold = 1, kinds = [1] } = this.opts;
8
+ if (kinds.includes(event.kind)) {
9
+ const [, replyToId] = ReplyBotPolicy.findReplyTag(event.tags) ?? [];
10
+ if (replyToId) {
11
+ const [prevEvent] = await store.query([{ ids: [replyToId] }], { signal });
12
+ if (prevEvent) {
13
+ const diff = event.created_at - prevEvent.created_at;
14
+ const pTag = prevEvent.tags.find(([name, value]) => name === "p" && value === event.pubkey);
15
+ if (diff <= threshold && !pTag) {
16
+ return ["OK", event.id, false, "rate-limited: replied too quickly"];
17
+ }
18
+ }
19
+ }
20
+ }
21
+ return ["OK", event.id, true, ""];
22
+ }
23
+ /** Tag is a NIP-10 root tag. */
24
+ static isRootTag(tag) {
25
+ return tag[0] === "e" && tag[3] === "root";
26
+ }
27
+ /** Tag is a NIP-10 reply tag. */
28
+ static isReplyTag(tag) {
29
+ return tag[0] === "e" && tag[3] === "reply";
30
+ }
31
+ /** Tag is an "e" tag without a NIP-10 marker. */
32
+ static isLegacyReplyTag(tag) {
33
+ return tag[0] === "e" && !tag[3];
34
+ }
35
+ /** Get the "e" tag for the event being replied to, first according to the NIPs then falling back to the legacy way. */
36
+ static findReplyTag(tags) {
37
+ return tags.find(this.isReplyTag) || tags.find(this.isRootTag) || tags.findLast(this.isLegacyReplyTag);
38
+ }
39
+ }
40
+ export {
41
+ ReplyBotPolicy
42
+ };
@@ -0,0 +1,62 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
2
+
3
+ /** Options for the ReplyBotPolicy. */
4
+ export interface ReplyBotPolicyOpts {
5
+ /** The store to use for fetching events. */
6
+ store: NStore;
7
+ /** The minimum time in seconds between two posts. */
8
+ threshold?: number;
9
+ /** The kinds of events to apply the policy to. */
10
+ kinds?: number[];
11
+ }
12
+
13
+ /** Block events that reply too quickly to another event. */
14
+ export class ReplyBotPolicy implements NPolicy {
15
+ private opts: ReplyBotPolicyOpts;
16
+ constructor(opts: ReplyBotPolicyOpts) {
17
+ this.opts = opts;
18
+ }
19
+
20
+ async call(event: NostrEvent, signal?: AbortSignal): Promise<NostrRelayOK> {
21
+ const { store, threshold = 1, kinds = [1] } = this.opts;
22
+
23
+ if (kinds.includes(event.kind)) {
24
+ const [, replyToId] = ReplyBotPolicy.findReplyTag(event.tags) ?? [];
25
+
26
+ if (replyToId) {
27
+ const [prevEvent] = await store.query([{ ids: [replyToId] }], { signal });
28
+
29
+ if (prevEvent) {
30
+ const diff = event.created_at - prevEvent.created_at;
31
+ const pTag = prevEvent.tags.find(([name, value]: string[]) => name === 'p' && value === event.pubkey);
32
+
33
+ if (diff <= threshold && !pTag) {
34
+ return ['OK', event.id, false, 'rate-limited: replied too quickly'];
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ return ['OK', event.id, true, ''];
41
+ }
42
+
43
+ /** Tag is a NIP-10 root tag. */
44
+ private static isRootTag(tag: string[]): tag is ['e', string, string, 'root', ...string[]] {
45
+ return tag[0] === 'e' && tag[3] === 'root';
46
+ }
47
+
48
+ /** Tag is a NIP-10 reply tag. */
49
+ private static isReplyTag(tag: string[]): tag is ['e', string, string, 'reply', ...string[]] {
50
+ return tag[0] === 'e' && tag[3] === 'reply';
51
+ }
52
+
53
+ /** Tag is an "e" tag without a NIP-10 marker. */
54
+ private static isLegacyReplyTag(tag: string[]): tag is ['e', string, string] {
55
+ return tag[0] === 'e' && !tag[3];
56
+ }
57
+
58
+ /** Get the "e" tag for the event being replied to, first according to the NIPs then falling back to the legacy way. */
59
+ private static findReplyTag(tags: string[][]): ['e', ...string[]] | undefined {
60
+ return tags.find(this.isReplyTag) || tags.find(this.isRootTag) || tags.findLast(this.isLegacyReplyTag);
61
+ }
62
+ }
@@ -0,0 +1,23 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ /** Policy options for `SizePolicy`. */
3
+ interface SizePolicyOpts {
4
+ /** Maximum size of the message content in bytes. Default: 8192 (8KB) */
5
+ maxBytes?: number;
6
+ }
7
+ /**
8
+ * Reject events larger than a specified size in bytes.
9
+ *
10
+ * ```ts
11
+ * // Reject events larger than the default size (8KB) .
12
+ * new SizePolicy();
13
+ * // Reject events larger than a custom size (15KB).
14
+ * new SizePolicy({ maxBytes: 15 * 1024 });
15
+ * ```
16
+ */
17
+ export declare class SizePolicy implements NPolicy {
18
+ private opts;
19
+ constructor(opts?: SizePolicyOpts);
20
+ call(event: NostrEvent): Promise<NostrRelayOK>;
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=SizePolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SizePolicy.d.ts","sourceRoot":"","sources":["../SizePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEzE,uCAAuC;AACvC,UAAU,cAAc;IACtB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAW,YAAW,OAAO;IACxC,OAAO,CAAC,IAAI,CAAiB;gBAEjB,IAAI,GAAE,cAAmB;IAK/B,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CAYrD"}
@@ -0,0 +1,19 @@
1
+ class SizePolicy {
2
+ opts;
3
+ constructor(opts = {}) {
4
+ this.opts = opts;
5
+ }
6
+ // deno-lint-ignore require-await
7
+ async call(event) {
8
+ const { maxBytes = 8 * 1024 } = this.opts;
9
+ const json = JSON.stringify(event);
10
+ const size = new TextEncoder().encode(json).length;
11
+ if (size > maxBytes) {
12
+ return ["OK", event.id, false, `blocked: event is too large`];
13
+ }
14
+ return ["OK", event.id, true, ""];
15
+ }
16
+ }
17
+ export {
18
+ SizePolicy
19
+ };
@@ -0,0 +1,39 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+
3
+ /** Policy options for `SizePolicy`. */
4
+ interface SizePolicyOpts {
5
+ /** Maximum size of the message content in bytes. Default: 8192 (8KB) */
6
+ maxBytes?: number;
7
+ }
8
+
9
+ /**
10
+ * Reject events larger than a specified size in bytes.
11
+ *
12
+ * ```ts
13
+ * // Reject events larger than the default size (8KB) .
14
+ * new SizePolicy();
15
+ * // Reject events larger than a custom size (15KB).
16
+ * new SizePolicy({ maxBytes: 15 * 1024 });
17
+ * ```
18
+ */
19
+ export class SizePolicy implements NPolicy {
20
+ private opts: SizePolicyOpts;
21
+
22
+ constructor(opts: SizePolicyOpts = {}) {
23
+ this.opts = opts;
24
+ }
25
+
26
+ // deno-lint-ignore require-await
27
+ async call(event: NostrEvent): Promise<NostrRelayOK> {
28
+ const { maxBytes = 8 * 1024 } = this.opts;
29
+
30
+ const json = JSON.stringify(event);
31
+ const size = new TextEncoder().encode(json).length;
32
+
33
+ if (size > maxBytes) {
34
+ return ['OK', event.id, false, `blocked: event is too large`];
35
+ }
36
+
37
+ return ['OK', event.id, true, ''];
38
+ }
39
+ }
@@ -0,0 +1,16 @@
1
+ import type { NostrEvent, NostrRelayInfo, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+ /**
3
+ * Allows only the listed pubkeys to post. All other events are rejected.
4
+ *
5
+ * ```ts
6
+ * // Only the given pubkey may post.
7
+ * new WhitelistPolicy(['e810fafa1e89cdf80cced8e013938e87e21b699b24c8570537be92aec4b12c18']);
8
+ * ```
9
+ */
10
+ export declare class WhitelistPolicy implements NPolicy {
11
+ private pubkeys;
12
+ constructor(pubkeys: Iterable<string>);
13
+ call({ id, pubkey }: NostrEvent): Promise<NostrRelayOK>;
14
+ get info(): NostrRelayInfo;
15
+ }
16
+ //# sourceMappingURL=WhitelistPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WhitelistPolicy.d.ts","sourceRoot":"","sources":["../WhitelistPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEzF;;;;;;;GAOG;AACH,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,OAAO,CAAmB;gBAEtB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC;IAK/B,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAU7D,IAAI,IAAI,IAAI,cAAc,CAMzB;CACF"}
@@ -0,0 +1,25 @@
1
+ class WhitelistPolicy {
2
+ pubkeys;
3
+ constructor(pubkeys) {
4
+ this.pubkeys = pubkeys;
5
+ }
6
+ // deno-lint-ignore require-await
7
+ async call({ id, pubkey }) {
8
+ for (const p of this.pubkeys) {
9
+ if (p === pubkey) {
10
+ return ["OK", id, true, ""];
11
+ }
12
+ }
13
+ return ["OK", id, false, "blocked: only certain pubkeys are allowed to post"];
14
+ }
15
+ get info() {
16
+ return {
17
+ limitation: {
18
+ restricted_writes: true
19
+ }
20
+ };
21
+ }
22
+ }
23
+ export {
24
+ WhitelistPolicy
25
+ };
@@ -0,0 +1,36 @@
1
+ import type { NostrEvent, NostrRelayInfo, NostrRelayOK, NPolicy } from '@nostrify/types';
2
+
3
+ /**
4
+ * Allows only the listed pubkeys to post. All other events are rejected.
5
+ *
6
+ * ```ts
7
+ * // Only the given pubkey may post.
8
+ * new WhitelistPolicy(['e810fafa1e89cdf80cced8e013938e87e21b699b24c8570537be92aec4b12c18']);
9
+ * ```
10
+ */
11
+ export class WhitelistPolicy implements NPolicy {
12
+ private pubkeys: Iterable<string>;
13
+
14
+ constructor(pubkeys: Iterable<string>) {
15
+ this.pubkeys = pubkeys;
16
+ }
17
+
18
+ // deno-lint-ignore require-await
19
+ async call({ id, pubkey }: NostrEvent): Promise<NostrRelayOK> {
20
+ for (const p of this.pubkeys) {
21
+ if (p === pubkey) {
22
+ return ['OK', id, true, ''];
23
+ }
24
+ }
25
+
26
+ return ['OK', id, false, 'blocked: only certain pubkeys are allowed to post'];
27
+ }
28
+
29
+ get info(): NostrRelayInfo {
30
+ return {
31
+ limitation: {
32
+ restricted_writes: true,
33
+ },
34
+ };
35
+ }
36
+ }
@@ -0,0 +1,26 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
2
+ /** Options for the `WoTPolicy`. */
3
+ interface WoTPolicyOpts {
4
+ /** Store to get kind 3 follow lists from. */
5
+ store: NStore;
6
+ /** Initial set of trusted pubkeys to query follow lists for. */
7
+ pubkeys: Iterable<string>;
8
+ /**
9
+ * How many levels of follow lists to query.
10
+ * `0` will just whitelist the given `pubkeys` without checking their follow lists.
11
+ * `1` will query their follows,
12
+ * `2` will query their follows follows, etc.
13
+ */
14
+ depth: number;
15
+ }
16
+ /** Whitelist pubkeys the given user follows, people those users follow, etc. up to `depth`. */
17
+ export declare class WoTPolicy implements NPolicy {
18
+ private pubkeys;
19
+ private opts;
20
+ constructor(opts: WoTPolicyOpts);
21
+ call(event: NostrEvent): Promise<NostrRelayOK>;
22
+ /** Retrieve the complete set of pubkeys to whitelist. */
23
+ private getPubkeys;
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=WoTPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WoTPolicy.d.ts","sourceRoot":"","sources":["../WoTPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEjF,mCAAmC;AACnC,UAAU,aAAa;IACrB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+FAA+F;AAC/F,qBAAa,SAAU,YAAW,OAAO;IACvC,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,IAAI,CAAgB;gBAEhB,IAAI,EAAE,aAAa;IAIzB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAWpD,yDAAyD;YAC3C,UAAU;CAyBzB"}
@@ -0,0 +1,39 @@
1
+ class WoTPolicy {
2
+ pubkeys;
3
+ opts;
4
+ constructor(opts) {
5
+ this.opts = opts;
6
+ }
7
+ async call(event) {
8
+ this.pubkeys ??= this.getPubkeys();
9
+ const pubkeys = await this.pubkeys;
10
+ if (pubkeys.has(event.pubkey)) {
11
+ return ["OK", event.id, true, ""];
12
+ }
13
+ return ["OK", event.id, false, "blocked: only certain pubkeys are allowed to post"];
14
+ }
15
+ /** Retrieve the complete set of pubkeys to whitelist. */
16
+ async getPubkeys() {
17
+ const { store, depth } = this.opts;
18
+ const pubkeys = /* @__PURE__ */ new Set([...this.opts.pubkeys]);
19
+ const authors = new Set(pubkeys);
20
+ for (let i = 0; i < depth; i++) {
21
+ const events = await store.query([{ kinds: [3], authors: [...authors] }]);
22
+ authors.clear();
23
+ for (const event of events) {
24
+ for (const [name, value] of event.tags) {
25
+ if (name === "p") {
26
+ if (!pubkeys.has(value)) {
27
+ authors.add(value);
28
+ }
29
+ pubkeys.add(value);
30
+ }
31
+ }
32
+ }
33
+ }
34
+ return pubkeys;
35
+ }
36
+ }
37
+ export {
38
+ WoTPolicy
39
+ };
@@ -0,0 +1,64 @@
1
+ import type { NostrEvent, NostrRelayOK, NPolicy, NStore } from '@nostrify/types';
2
+
3
+ /** Options for the `WoTPolicy`. */
4
+ interface WoTPolicyOpts {
5
+ /** Store to get kind 3 follow lists from. */
6
+ store: NStore;
7
+ /** Initial set of trusted pubkeys to query follow lists for. */
8
+ pubkeys: Iterable<string>;
9
+ /**
10
+ * How many levels of follow lists to query.
11
+ * `0` will just whitelist the given `pubkeys` without checking their follow lists.
12
+ * `1` will query their follows,
13
+ * `2` will query their follows follows, etc.
14
+ */
15
+ depth: number;
16
+ }
17
+
18
+ /** Whitelist pubkeys the given user follows, people those users follow, etc. up to `depth`. */
19
+ export class WoTPolicy implements NPolicy {
20
+ private pubkeys: Promise<Set<string>> | undefined;
21
+ private opts: WoTPolicyOpts;
22
+
23
+ constructor(opts: WoTPolicyOpts) {
24
+ this.opts = opts;
25
+ }
26
+
27
+ async call(event: NostrEvent): Promise<NostrRelayOK> {
28
+ this.pubkeys ??= this.getPubkeys();
29
+ const pubkeys = await this.pubkeys;
30
+
31
+ if (pubkeys.has(event.pubkey)) {
32
+ return ['OK', event.id, true, ''];
33
+ }
34
+
35
+ return ['OK', event.id, false, 'blocked: only certain pubkeys are allowed to post'];
36
+ }
37
+
38
+ /** Retrieve the complete set of pubkeys to whitelist. */
39
+ private async getPubkeys(): Promise<Set<string>> {
40
+ const { store, depth } = this.opts;
41
+
42
+ const pubkeys = new Set<string>([...this.opts.pubkeys]);
43
+ const authors = new Set(pubkeys);
44
+
45
+ for (let i = 0; i < depth; i++) {
46
+ const events = await store.query([{ kinds: [3], authors: [...authors] }]);
47
+
48
+ authors.clear();
49
+
50
+ for (const event of events) {
51
+ for (const [name, value] of event.tags) {
52
+ if (name === 'p') {
53
+ if (!pubkeys.has(value)) { // Avoid infinite loops.
54
+ authors.add(value);
55
+ }
56
+ pubkeys.add(value);
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ return pubkeys;
63
+ }
64
+ }