open-secrets-sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
A decentralized protocol for anonymous confessions, built on Nostr.
|
|
4
4
|
|
|
5
|
+
## Our Philosophy
|
|
6
|
+
|
|
7
|
+
Confession websites are ephemeral. They start empty, grow briefly, and eventually die, taking years of human secrets and community with them.
|
|
8
|
+
|
|
9
|
+
**Open Secrets** was created to end this cycle. By moving the "database" of secrets to a decentralized network (Nostr), we ensure that:
|
|
10
|
+
- **Communities Never Die**: If your favorite confession site goes offline, the data remains. A new client can spin up and instantly restore the entire community history.
|
|
11
|
+
- **Global Repository**: We are building a permanent, global archive of anonymous human experiences that no single entity owns or can delete.
|
|
12
|
+
- **Cross-App discovery**: A secret posted on one app can be discovered and discussed on another, creating a massive, interconnected network of anonymous talk.
|
|
13
|
+
|
|
5
14
|
## Installation
|
|
6
15
|
|
|
7
16
|
```bash
|
|
@@ -23,13 +32,7 @@ const tags = createOpenSecretsTags({
|
|
|
23
32
|
client: 'my-awesome-app'
|
|
24
33
|
});
|
|
25
34
|
|
|
26
|
-
// Use with nostr-tools
|
|
27
|
-
const event = {
|
|
28
|
-
kind: 1,
|
|
29
|
-
content: "This is my secret...",
|
|
30
|
-
tags: tags,
|
|
31
|
-
created_at: Math.floor(Date.now() / 1000)
|
|
32
|
-
};
|
|
35
|
+
// Use with nostr-tools to sign and publish
|
|
33
36
|
```
|
|
34
37
|
|
|
35
38
|
### Parsing metadata
|
|
@@ -39,16 +42,73 @@ import { parseOpenSecretsTags } from 'open-secrets-sdk';
|
|
|
39
42
|
|
|
40
43
|
const metadata = parseOpenSecretsTags(event.tags);
|
|
41
44
|
console.log(metadata.gender); // 'female'
|
|
42
|
-
console.log(metadata.client); // 'my-awesome-app'
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
## Building a Client
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
To build a barebones client, you need to query Nostr relays for events with the `#t: open-secrets` tag.
|
|
50
|
+
|
|
51
|
+
### Simple Frontend Example (React-ish)
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
import { SimplePool } from 'nostr-tools';
|
|
55
|
+
import { getOpenSecretsFilter, parseOpenSecretsTags } from 'open-secrets-sdk';
|
|
56
|
+
|
|
57
|
+
const relays = ['wss://nos.lol', 'wss://relay.damus.io'];
|
|
58
|
+
const pool = new SimplePool();
|
|
59
|
+
|
|
60
|
+
async function fetchSecrets() {
|
|
61
|
+
const filter = getOpenSecretsFilter(50);
|
|
62
|
+
const events = await pool.querySync(relays, filter);
|
|
63
|
+
|
|
64
|
+
return events.map(event => ({
|
|
65
|
+
...event,
|
|
66
|
+
metadata: parseOpenSecretsTags(event.tags)
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Moderation & Safety
|
|
72
|
+
|
|
73
|
+
### The Decentralized Reality
|
|
74
|
+
Because Open Secrets is decentralized, **no one can delete a post from the network once it is published.** There is no central admin who can "wipe" undesirable content.
|
|
75
|
+
|
|
76
|
+
### Client-Side Defense (The "Gatekeeper" Role)
|
|
77
|
+
As a client developer, you are the editor of your own app. You have the power (and responsibility) to decide what your users see.
|
|
78
|
+
|
|
79
|
+
**Since you cannot censor the protocol, you must filter the view.**
|
|
80
|
+
|
|
81
|
+
#### 1. NSFW Handling
|
|
82
|
+
Always check the `isNsfw` flag on the metadata. You can choose to blur these posts or hide them entirely by default.
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
const postsToShow = allPosts.filter(p => !p.metadata.isNsfw);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 2. Content Removals (Reporting)
|
|
89
|
+
Since every post uses a fresh identity, blacklisting users is impossible. However, you can maintain a local list of problematic `event.id`s (e.g., from reports) to hide specific posts that violate your app's rules.
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
const REMOVED_IDS = ['event_id_1', 'event_id_2'];
|
|
93
|
+
const filteredPosts = posts.filter(p => !REMOVED_IDS.includes(p.id));
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### 3. Trust-Based Filtering (Client Allowlist)
|
|
97
|
+
If you want to be stricter, you can choose to only display posts that originated from "trusted" clients.
|
|
98
|
+
|
|
99
|
+
**Note on Trusted Clients**: Some client may use a "publish first, moderate later" approach to ensure a 100% censorship-resistant archive. This means a trusted client *will* still broadcast everything to Nostr, but will hide problematic posts in its own UI once its filters catch up. As a developer, you should always combine client trust with your own local filters.
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const TRUSTED_CLIENTS = ['lapregunta', 'trusted-app-1'];
|
|
103
|
+
const verifiedPosts = posts.filter(p => TRUSTED_CLIENTS.includes(p.metadata.client));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 3. Content Filtering
|
|
107
|
+
Since it's anonymous text, you can run simple keyword filters before rendering the content to the user.
|
|
49
108
|
|
|
50
|
-
|
|
51
|
-
|
|
109
|
+
```javascript
|
|
110
|
+
const BAD_WORDS = ['...'];
|
|
111
|
+
const safePosts = posts.filter(p => !BAD_WORDS.some(word => p.content.includes(word)));
|
|
52
112
|
```
|
|
53
113
|
|
|
54
114
|
## Protocol Details
|