epistery 1.0.0
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/Architecture.md +84 -0
- package/CLI.md +291 -0
- package/LICENSE +21 -0
- package/MONGODB_GOTCHA.md +69 -0
- package/README.md +50 -0
- package/SESSION.md +98 -0
- package/cli/epistery.mjs +576 -0
- package/client/client.js +18 -0
- package/client/ethers.js +24441 -0
- package/client/ethers.min.js +1 -0
- package/client/export.js +67 -0
- package/client/status.html +707 -0
- package/client/wallet.js +213 -0
- package/client/witness.js +663 -0
- package/contracts/agent.sol +108 -0
- package/default.ini +14 -0
- package/docs/EpisteryModuleConfig.md +317 -0
- package/docs/blog-unified-config.md +125 -0
- package/hardhat.config.js +33 -0
- package/index.mjs +385 -0
- package/package.json +46 -0
- package/scripts/deploy-agent.js +33 -0
- package/scripts/verify-agent.js +39 -0
- package/src/epistery.ts +275 -0
- package/src/utils/Aqua.ts +194 -0
- package/src/utils/CliWallet.ts +334 -0
- package/src/utils/Config.ts +196 -0
- package/src/utils/Utils.ts +571 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/types.ts +114 -0
- package/test/README.md +50 -0
- package/test/index.html +13 -0
- package/test/package.json +15 -0
- package/test/server.mjs +87 -0
- package/tsconfig.json +26 -0
package/Architecture.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Plug in architecture
|
|
2
|
+
|
|
3
|
+
This module is a plugin. It provides a host with data-wallet services exposed through
|
|
4
|
+
host.tld/.well-known/epistery. Epistery will create wallets for both the client (browser)
|
|
5
|
+
and the server if not otherwise provided. It provides the foundation methods for creating,
|
|
6
|
+
validating and manipulating data-wallets.
|
|
7
|
+
|
|
8
|
+
Server code is available through web calls. The
|
|
9
|
+
client is implemented with a browser script available from client.js.
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
This is a typescript project build on express.
|
|
13
|
+
|
|
14
|
+
| path | description |
|
|
15
|
+
|------------------------|------------------------------------------------------------------------------------------------------------------|
|
|
16
|
+
| /index.mjs | Entry point harness |
|
|
17
|
+
| /client | Assets and scripts intended to be embedded in the browser page |
|
|
18
|
+
| /client/client.js | client-side counterpart to /epistery.ts. |
|
|
19
|
+
| /client/ethers.js | Core blockchain tools |
|
|
20
|
+
| /client/status.html | The template page rendered by /.well-known/epistery/status. This is the only human readable content presented by /.epistery |
|
|
21
|
+
| /client/witness.js | |
|
|
22
|
+
| /src | implementation |
|
|
23
|
+
| /src/controllers/ | Controllers provide discreet services usually behind a named route /.well-known/epistery/[controller] |
|
|
24
|
+
| /src/utils | Shared tools that assist the controllers |
|
|
25
|
+
| /src/utils/Aqua.ts | Aqua protocol implementation that underlies the data wallet implementation |
|
|
26
|
+
| /src/utils/Config.ts | Interface to the $HOME/.epistory/config.ini and dependent configuration data |
|
|
27
|
+
| /src/utils/types.ts | Typescript common schema |
|
|
28
|
+
| /src/utils/Utils.ts | (Not sure. Seems like these methods should be attached to something with a named purpose |
|
|
29
|
+
| /src/utils/index.ts | Import root for reach all utilities |
|
|
30
|
+
| /src/epistery.ts | Root class that is connected by the host |
|
|
31
|
+
| /test | A barebones host application to provide sample code and exercise the features |
|
|
32
|
+
| /default.ini | template configuration for initialising a new installation |
|
|
33
|
+
|
|
34
|
+
>NOTE: api.ts is left out. I propose that if we want a standalone generic implementation of the epistery plugin,
|
|
35
|
+
> it should be implemented in a separate repo.
|
|
36
|
+
|
|
37
|
+
## Data Wallets
|
|
38
|
+
The core purpose of the epistery plugin is manage the creation and manipulation of data wallets. This manifests as api's
|
|
39
|
+
invoked by the browser and partner sites
|
|
40
|
+
|
|
41
|
+
All of the Data Wallet functionality is found in the in /src/controllers/DataWalletController, operating behind .well-known/epistery/data. Utils
|
|
42
|
+
is used for common cryto functionaility and other tools
|
|
43
|
+
|
|
44
|
+
## Signing Wallets
|
|
45
|
+
|
|
46
|
+
## Config File
|
|
47
|
+
System configuration is managed with ini files in $HOME/.epistery. The root defines config.ini which has system wide
|
|
48
|
+
settings. The default settings are captured in default.ini. Each domain that has been initialized will have a folder
|
|
49
|
+
with it's own config.ini file, as well as key files and other persistent settings.
|
|
50
|
+
|
|
51
|
+
The root config file is structured into the following sections
|
|
52
|
+
|
|
53
|
+
```ini
|
|
54
|
+
[profile]
|
|
55
|
+
name=
|
|
56
|
+
email=
|
|
57
|
+
[ipfs]
|
|
58
|
+
url=https://rootz.digital/api/v0
|
|
59
|
+
[default.provider]
|
|
60
|
+
// When a domain is initialized, it defaults to this provide info which is subsequencly saved with the domain config.ini
|
|
61
|
+
chainId=
|
|
62
|
+
name=
|
|
63
|
+
rpc=
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
A domain config file, like `$HOME/.epistery/mydomain.com/config.ini`, includes:
|
|
67
|
+
|
|
68
|
+
```ini
|
|
69
|
+
[provider]
|
|
70
|
+
chainId=
|
|
71
|
+
name=
|
|
72
|
+
rpc=
|
|
73
|
+
|
|
74
|
+
[wallet]
|
|
75
|
+
address=
|
|
76
|
+
mnemonic=
|
|
77
|
+
publicKey=
|
|
78
|
+
privateKey=
|
|
79
|
+
|
|
80
|
+
[ssl]
|
|
81
|
+
key=
|
|
82
|
+
cert=
|
|
83
|
+
modified=
|
|
84
|
+
```
|
package/CLI.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Epistery CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for Epistery authentication and requests.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Initialize a domain (creates wallet in ~/.epistery/{domain}/)
|
|
9
|
+
epistery initialize localhost
|
|
10
|
+
|
|
11
|
+
# Set as default
|
|
12
|
+
epistery set-default localhost
|
|
13
|
+
|
|
14
|
+
# Make authenticated requests (automatic key exchange on first use)
|
|
15
|
+
epistery curl https://wiki.rootz.global/wiki/Home
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
### `epistery initialize <domain>`
|
|
21
|
+
|
|
22
|
+
Initialize a domain with a new wallet. Creates `~/.epistery/{domain}/config.ini` with:
|
|
23
|
+
- Wallet (address, keys, mnemonic)
|
|
24
|
+
- Provider configuration (from `~/.epistery/config.ini` default)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
epistery initialize localhost
|
|
28
|
+
epistery initialize wiki.rootz.global
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### `epistery curl [options] <url>`
|
|
32
|
+
|
|
33
|
+
Make authenticated HTTP request. Automatically performs key exchange on first use.
|
|
34
|
+
|
|
35
|
+
**Options:**
|
|
36
|
+
- `-w, --wallet <domain>` - Use specific domain (overrides default)
|
|
37
|
+
- `-X, --request <method>` - HTTP method (default: GET)
|
|
38
|
+
- `-d, --data <data>` - Request body data
|
|
39
|
+
- `-H, --header <header>` - Additional headers
|
|
40
|
+
- `-b, --bot` - Use bot auth header (default: session cookie)
|
|
41
|
+
- `-v, --verbose` - Show detailed output
|
|
42
|
+
|
|
43
|
+
**Examples:**
|
|
44
|
+
```bash
|
|
45
|
+
# GET request (uses default domain)
|
|
46
|
+
epistery curl https://wiki.rootz.global/wiki/Home
|
|
47
|
+
|
|
48
|
+
# Use specific domain
|
|
49
|
+
epistery curl -w localhost https://localhost:4080/session/context
|
|
50
|
+
|
|
51
|
+
# POST request
|
|
52
|
+
epistery curl -X POST -d '{"title":"Test","body":"# Test"}' https://wiki.rootz.global/wiki/Test
|
|
53
|
+
|
|
54
|
+
# Bot mode (no session, sign per request)
|
|
55
|
+
epistery curl --bot https://wiki.rootz.global/session/context
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### `epistery info [domain]`
|
|
59
|
+
|
|
60
|
+
Show domain information (wallet address, provider, session status).
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
epistery info # Show default domain
|
|
64
|
+
epistery info localhost # Show specific domain
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `epistery set-default <domain>`
|
|
68
|
+
|
|
69
|
+
Set default domain for CLI operations.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
epistery set-default localhost
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Architecture
|
|
76
|
+
|
|
77
|
+
### Domain-Based Configuration
|
|
78
|
+
|
|
79
|
+
Epistery CLI uses the same domain configuration system as the server:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
~/.epistery/
|
|
83
|
+
├── config.ini # Root config with [cli] section
|
|
84
|
+
│ └── [cli]
|
|
85
|
+
│ └── default_domain=localhost
|
|
86
|
+
├── localhost/
|
|
87
|
+
│ ├── config.ini # Domain config with wallet & provider
|
|
88
|
+
│ └── session.json # Session cookie (auto-created)
|
|
89
|
+
└── wiki.rootz.global/
|
|
90
|
+
├── config.ini
|
|
91
|
+
└── session.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Authentication Modes
|
|
95
|
+
|
|
96
|
+
**Session Cookie (Default):**
|
|
97
|
+
- Performs key exchange once, saves session cookie
|
|
98
|
+
- Subsequent requests use cookie
|
|
99
|
+
- Best for multiple requests to same server
|
|
100
|
+
|
|
101
|
+
**Bot Auth Header (`--bot`):**
|
|
102
|
+
- Signs each request individually
|
|
103
|
+
- No session management
|
|
104
|
+
- Best for distributed systems or one-off requests
|
|
105
|
+
|
|
106
|
+
### Automatic Key Exchange
|
|
107
|
+
|
|
108
|
+
The `curl` command automatically performs key exchange when needed:
|
|
109
|
+
|
|
110
|
+
1. Check for existing session in `~/.epistery/{domain}/session.json`
|
|
111
|
+
2. If no session, perform key exchange with server
|
|
112
|
+
3. Save session cookie for future requests
|
|
113
|
+
4. Make the actual HTTP request
|
|
114
|
+
|
|
115
|
+
No manual "connect" step required!
|
|
116
|
+
|
|
117
|
+
## Usage Patterns
|
|
118
|
+
|
|
119
|
+
### Local Development
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Initialize for local development
|
|
123
|
+
epistery initialize localhost
|
|
124
|
+
epistery set-default localhost
|
|
125
|
+
|
|
126
|
+
# Make requests
|
|
127
|
+
epistery curl https://localhost:4080/wiki/index
|
|
128
|
+
epistery curl -X PUT -d '{"title":"Test","body":"# Test"}' https://localhost:4080/wiki/Test
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Multiple Domains
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Initialize multiple domains
|
|
135
|
+
epistery initialize localhost
|
|
136
|
+
epistery initialize wiki.rootz.global
|
|
137
|
+
epistery initialize staging.example.com
|
|
138
|
+
|
|
139
|
+
# Switch between them
|
|
140
|
+
epistery curl -w localhost https://localhost:4080/...
|
|
141
|
+
epistery curl -w wiki.rootz.global https://wiki.rootz.global/...
|
|
142
|
+
epistery curl -w staging.example.com https://staging.example.com/...
|
|
143
|
+
|
|
144
|
+
# Or set default and omit -w
|
|
145
|
+
epistery set-default wiki.rootz.global
|
|
146
|
+
epistery curl https://wiki.rootz.global/...
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Bot/Agent Applications
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
import { CliWallet } from 'epistery';
|
|
153
|
+
|
|
154
|
+
// Load domain wallet
|
|
155
|
+
const wallet = CliWallet.load('localhost'); // or CliWallet.load() for default
|
|
156
|
+
|
|
157
|
+
// Create bot auth header
|
|
158
|
+
const authHeader = await wallet.createBotAuthHeader();
|
|
159
|
+
|
|
160
|
+
// Make request
|
|
161
|
+
const response = await fetch('https://localhost:4080/wiki/Home', {
|
|
162
|
+
headers: { 'Authorization': authHeader }
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Configuration Files
|
|
167
|
+
|
|
168
|
+
### Root Config (`~/.epistery/config.ini`)
|
|
169
|
+
|
|
170
|
+
```ini
|
|
171
|
+
[profile]
|
|
172
|
+
name=
|
|
173
|
+
email=
|
|
174
|
+
|
|
175
|
+
[ipfs]
|
|
176
|
+
url=https://rootz.digital/api/v0
|
|
177
|
+
|
|
178
|
+
[default.provider]
|
|
179
|
+
chainId=420420422,
|
|
180
|
+
name=polkadot-hub-testnet
|
|
181
|
+
rpc=https://testnet-passet-hub-eth-rpc.polkadot.io
|
|
182
|
+
|
|
183
|
+
[cli]
|
|
184
|
+
default_domain=localhost
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Domain Config (`~/.epistery/{domain}/config.ini`)
|
|
188
|
+
|
|
189
|
+
```ini
|
|
190
|
+
[domain]
|
|
191
|
+
domain=localhost
|
|
192
|
+
|
|
193
|
+
[wallet]
|
|
194
|
+
address=0x...
|
|
195
|
+
mnemonic=word word word...
|
|
196
|
+
publicKey=0x04...
|
|
197
|
+
privateKey=0x...
|
|
198
|
+
|
|
199
|
+
[provider]
|
|
200
|
+
chainId=420420422,
|
|
201
|
+
name=polkadot-hub-testnet
|
|
202
|
+
rpc=https://testnet-passet-hub-eth-rpc.polkadot.io
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Session File (`~/.epistery/{domain}/session.json`)
|
|
206
|
+
|
|
207
|
+
Auto-created by `epistery curl`:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"domain": "https://wiki.rootz.global",
|
|
212
|
+
"cookie": "session_token_here",
|
|
213
|
+
"authenticated": true,
|
|
214
|
+
"timestamp": "2025-01-10T12:00:00.000Z"
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Security
|
|
219
|
+
|
|
220
|
+
- Domain configs stored with 0600 permissions (user only)
|
|
221
|
+
- Private keys never transmitted (only signatures)
|
|
222
|
+
- Each domain has its own isolated wallet
|
|
223
|
+
- Session cookies saved securely per domain
|
|
224
|
+
|
|
225
|
+
## Design Philosophy
|
|
226
|
+
|
|
227
|
+
The Epistery CLI uses a unified command structure with subcommands:
|
|
228
|
+
- ✅ Uses existing Epistery domain config system
|
|
229
|
+
- ✅ Consistent with server-side architecture
|
|
230
|
+
- ✅ Automatic key exchange (no manual connect step)
|
|
231
|
+
- ✅ Default domain support (less typing)
|
|
232
|
+
- ✅ Simpler mental model (domain = wallet)
|
|
233
|
+
|
|
234
|
+
## Examples
|
|
235
|
+
|
|
236
|
+
### Initialize and Use
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Setup
|
|
240
|
+
epistery initialize localhost
|
|
241
|
+
epistery set-default localhost
|
|
242
|
+
|
|
243
|
+
# Use
|
|
244
|
+
epistery curl https://wiki.rootz.global/wiki/Home
|
|
245
|
+
epistery curl https://wiki.rootz.global/wiki/index
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Multiple Domains
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Setup each environment
|
|
252
|
+
epistery initialize dev.example.com
|
|
253
|
+
epistery initialize staging.example.com
|
|
254
|
+
epistery initialize prod.example.com
|
|
255
|
+
|
|
256
|
+
# Use different environments
|
|
257
|
+
epistery curl -w dev.example.com https://dev.example.com/api/status
|
|
258
|
+
epistery curl -w staging.example.com https://staging.example.com/api/status
|
|
259
|
+
epistery curl -w prod.example.com https://prod.example.com/api/status
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Bot Mode
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Bot mode doesn't need session, signs each request
|
|
266
|
+
epistery curl --bot https://wiki.rootz.global/session/context
|
|
267
|
+
epistery curl --bot -X POST -d '{"title":"Log","body":"# Entry"}' https://wiki.rootz.global/wiki/Log
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Troubleshooting
|
|
271
|
+
|
|
272
|
+
**"Domain not found or has no wallet"**
|
|
273
|
+
- Run `epistery initialize <domain>` first
|
|
274
|
+
|
|
275
|
+
**"Key exchange failed"**
|
|
276
|
+
- Check server is running and accessible
|
|
277
|
+
- Verify URL is correct
|
|
278
|
+
- Use `-v` flag for detailed output
|
|
279
|
+
|
|
280
|
+
**"Failed to obtain session cookie"**
|
|
281
|
+
- Server may not be setting cookies
|
|
282
|
+
- Try `--bot` mode instead
|
|
283
|
+
- Check server configuration
|
|
284
|
+
|
|
285
|
+
## Integration
|
|
286
|
+
|
|
287
|
+
The CLI is designed to work with:
|
|
288
|
+
- **Rhonda** - Wiki with Epistery authentication
|
|
289
|
+
- **Any Epistery-enabled app** - Just initialize and curl!
|
|
290
|
+
|
|
291
|
+
Server-side apps should implement bot authentication handler (see Rhonda's account-server for example).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 rootz-global
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# MongoDB Object _id Field Order Sensitivity
|
|
2
|
+
|
|
3
|
+
## The Problem
|
|
4
|
+
|
|
5
|
+
MongoDB treats object `_id` fields as **order-sensitive**. This means:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
{_id: {a: "root", d: "Home"}} // Different from...
|
|
9
|
+
{_id: {d: "Home", a: "root"}} // ...this!
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
These are considered **two different documents** even though they have the same fields and values.
|
|
13
|
+
|
|
14
|
+
## The Impact
|
|
15
|
+
|
|
16
|
+
When doing a PUT/upsert on the wiki, if you get the field order wrong in the `_id`, you will:
|
|
17
|
+
- ✅ NOT update the existing document
|
|
18
|
+
- ❌ CREATE a duplicate document with a different `_id` field order
|
|
19
|
+
- The original document remains unchanged and continues to be displayed
|
|
20
|
+
- Your new document becomes an orphan
|
|
21
|
+
|
|
22
|
+
## The Solution
|
|
23
|
+
|
|
24
|
+
**Always preserve the exact field order when constructing `_id` objects:**
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
// Correct for wiki doclets:
|
|
28
|
+
{_id: {d: "PageName", a: "accountName"}}
|
|
29
|
+
|
|
30
|
+
// WRONG - will create duplicate:
|
|
31
|
+
{_id: {a: "accountName", d: "PageName"}}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How to Avoid This
|
|
35
|
+
|
|
36
|
+
1. **Read first, update second**: Always GET the existing document first to see the exact `_id` structure
|
|
37
|
+
2. **Preserve field order**: When constructing updates, maintain the exact field order from the original
|
|
38
|
+
3. **Use string _id when possible**: Avoid compound object `_id` fields in new collections
|
|
39
|
+
|
|
40
|
+
## Cleaning Up Duplicates
|
|
41
|
+
|
|
42
|
+
If you accidentally create a duplicate:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Find duplicates
|
|
46
|
+
db.wiki.find({"_id.d": "PageName"})
|
|
47
|
+
|
|
48
|
+
// Delete the wrong one (check field order!)
|
|
49
|
+
db.wiki.deleteOne({_id: {a: "root", d: "PageName"}})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Why This Design?
|
|
53
|
+
|
|
54
|
+
This is an arcane MongoDB behavior that's a source of time-wasting bugs. String `_id` fields would be much safer.
|
|
55
|
+
|
|
56
|
+
## TODO: Fix in wiki-mixin
|
|
57
|
+
|
|
58
|
+
**Action item**: Normalize the `_id` field order in `@metric-im/wiki-mixin` API so clients never have to worry about this.
|
|
59
|
+
|
|
60
|
+
The wiki API should:
|
|
61
|
+
1. Always construct `_id` as `{d: docName, a: accountName}` regardless of input order
|
|
62
|
+
2. Normalize any incoming `_id` objects to this canonical order before MongoDB operations
|
|
63
|
+
3. Document the canonical order in API docs
|
|
64
|
+
|
|
65
|
+
This would prevent this issue for all wiki hosts and clients.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
*Documented 2025-10-14 after accidentally creating a duplicate Home page*
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Epistery
|
|
2
|
+
|
|
3
|
+
_Epistemology is the study of knowledge. An Epistery, it follows, is a place share the knowledge of knowledge._
|
|
4
|
+
|
|
5
|
+
This project is open source middleware that provides websites and browsers a shared neutral space to identify and
|
|
6
|
+
verify the origin of data and conduct digital business. It inserts the blockchain as a witness and clerk for the mundane
|
|
7
|
+
business of clicking, tipping, stamping and cloaking, currently run by commercial web gatekeepers.
|
|
8
|
+
|
|
9
|
+
Epistery provides the primitive tools for creating and rendering data-wallets.
|
|
10
|
+
|
|
11
|
+
* /.well-known/epistery - json data presenting the signing identity/wallet of the site
|
|
12
|
+
* /.well-known/epistery/status - human version of the above, plus overview of the site's activity and interactive features like comments, ratings.
|
|
13
|
+
* /.well-known/epistery/data/* - data-wallet module api for mint, manipulate, render and delete
|
|
14
|
+
* /.well-known/acme - Ephemeral ACME url for authorizing ssl cert assignment.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install epistery
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Initialize your domain:
|
|
23
|
+
```bash
|
|
24
|
+
npx epistery initialize mydomain.com
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
In your Express application:
|
|
28
|
+
```javascript
|
|
29
|
+
import express from 'express';
|
|
30
|
+
import https from 'https';
|
|
31
|
+
import { Epistery } from 'epistery';
|
|
32
|
+
|
|
33
|
+
const app = express();
|
|
34
|
+
|
|
35
|
+
// Connect and attach epistery
|
|
36
|
+
const epistery = await Epistery.connect();
|
|
37
|
+
await epistery.setDomain('mydomain.com');
|
|
38
|
+
await epistery.attach(app);
|
|
39
|
+
|
|
40
|
+
// Start your server
|
|
41
|
+
const https_server = https.createServer(epistery.config.SNI, app);
|
|
42
|
+
https_server.listen(443);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Data Wallets
|
|
46
|
+
|
|
47
|
+
A data wallet is data with chain. The data wallet attaches to the source object with a hash and is used to track
|
|
48
|
+
the provenance, manipulation and usage of the data, per instruction by the owner. The epistery enables IPFS as a
|
|
49
|
+
default storage option for uploaded objects, but there is no requirement to load the data itself on chain, just
|
|
50
|
+
its accounting.
|
package/SESSION.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
1# Epistery CLI Session Log
|
|
2
|
+
## Date: 2025-10-14
|
|
3
|
+
|
|
4
|
+
### Context
|
|
5
|
+
Building epistery CLI for authenticated requests to wiki.rootz.global. Hours of work building authentication system. Machine has crashed multiple times, losing session context.
|
|
6
|
+
|
|
7
|
+
### Current State
|
|
8
|
+
- **CLI Location**: `./cli/epistery.mjs`
|
|
9
|
+
- **Identity**: localhost wallet at `~/.epistery/localhost/config.ini`
|
|
10
|
+
- **Address**: `0x8df97495e72461786E263CaECcAf21315E98e9aF`
|
|
11
|
+
- **Default Domain**: Set to `localhost`
|
|
12
|
+
- **Authorization**: This address is authorized on wiki.rootz.global server
|
|
13
|
+
- **Recent Change**: Bot mode now defaults to `true` (was `false`) in cli/epistery.mjs line 127
|
|
14
|
+
|
|
15
|
+
### Goal
|
|
16
|
+
Post documentation to https://wiki.rootz.global/wiki/Home explaining how other developers can:
|
|
17
|
+
1. Set up epistery CLI
|
|
18
|
+
2. Configure authentication
|
|
19
|
+
3. Post to the wiki from their dev environment using Claude
|
|
20
|
+
|
|
21
|
+
### Current Issue
|
|
22
|
+
- ✅ Read works: `epistery curl https://wiki.rootz.global/wiki/Home`
|
|
23
|
+
- ❌ Write getting unauthorized (was working before crash)
|
|
24
|
+
|
|
25
|
+
### Commands That Work
|
|
26
|
+
```bash
|
|
27
|
+
epistery set-default localhost
|
|
28
|
+
epistery curl https://wiki.rootz.global/wiki/Home
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Debugging Progress
|
|
32
|
+
|
|
33
|
+
**Bot Mode (Authorization header):**
|
|
34
|
+
- ✅ Signature generation works
|
|
35
|
+
- ❌ Server returns 401 Unauthorized
|
|
36
|
+
- Format: `Authorization: Bot <base64 JSON with address, signature, message>`
|
|
37
|
+
|
|
38
|
+
**Session Mode (Key Exchange):**
|
|
39
|
+
- ✅ Key exchange completes successfully
|
|
40
|
+
- ✅ Server responds: 0x06E2174095fB7cb1251EEf4D229772A59a0C8761
|
|
41
|
+
- ❌ Returns `authenticated: false`
|
|
42
|
+
- ❌ No session cookie set by server
|
|
43
|
+
- This means the server doesn't recognize/trust the client address (9aF)
|
|
44
|
+
|
|
45
|
+
### Solution Found
|
|
46
|
+
|
|
47
|
+
The bot authentication in Rhonda's account-server (lines 825-909) expects:
|
|
48
|
+
1. User exists in database ✅
|
|
49
|
+
2. ACL exists for account access ✅
|
|
50
|
+
3. Signature verification ✅
|
|
51
|
+
|
|
52
|
+
The user needs to be marked as a system account. Update MongoDB:
|
|
53
|
+
```
|
|
54
|
+
db.user.updateOne(
|
|
55
|
+
{_id: '0x8df97495e72461786E263CaECcAf21315E98e9aF'},
|
|
56
|
+
{$set: {'options.systemAccount': true}}
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Next Steps
|
|
61
|
+
1. Update user record to mark as system account
|
|
62
|
+
2. Test bot authentication with CLI
|
|
63
|
+
3. Write and post developer documentation to wiki
|
|
64
|
+
|
|
65
|
+
### Resolution
|
|
66
|
+
|
|
67
|
+
**Fixed in `/home/msprague/workspace/rootz/rhonda/modules/account-server/index.mjs:866`**
|
|
68
|
+
|
|
69
|
+
Changed from:
|
|
70
|
+
```javascript
|
|
71
|
+
const userAccount = await this.userCollection.findOne({
|
|
72
|
+
address: address.toLowerCase()
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To:
|
|
77
|
+
```javascript
|
|
78
|
+
const userAccount = await this.userCollection.findOne({
|
|
79
|
+
address: new RegExp(`^${address}$`, 'i')
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This makes address lookup case-insensitive, handling addresses stored with mixed case in the database.
|
|
84
|
+
|
|
85
|
+
### Success
|
|
86
|
+
|
|
87
|
+
✅ Bot authentication working
|
|
88
|
+
✅ Test page created at `/wiki/ClaudeTest`
|
|
89
|
+
✅ Documentation updated on wiki Home page
|
|
90
|
+
✅ Other developers can now follow the instructions to set up their own agents
|
|
91
|
+
|
|
92
|
+
### Key Learnings
|
|
93
|
+
|
|
94
|
+
1. **Case sensitivity**: Ethereum addresses are case-insensitive but often stored with mixed case (checksummed). Always use case-insensitive comparison in MongoDB queries.
|
|
95
|
+
|
|
96
|
+
2. **Bot authentication flow**: The Epistery CLI signs each request with the wallet's private key. The server verifies the signature, looks up the user by address, checks ACL permissions, and allows/denies the request.
|
|
97
|
+
|
|
98
|
+
3. **Session persistence**: Creating SESSION.md files for important development sessions helps recover from machine crashes and provides documentation of debugging processes.
|