@evanp/activitypub-bot 0.13.0 → 0.13.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/package.json +2 -2
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/main.yml +0 -34
- package/.github/workflows/tag.yml +0 -106
- package/.nvmrc +0 -1
- package/Dockerfile +0 -17
- package/docs/activitypub.bot.drawio +0 -110
- package/tests/activitydistributor.test.js +0 -606
- package/tests/activityhandler.test.js +0 -2276
- package/tests/activitypubclient.test.js +0 -210
- package/tests/actorstorage.test.js +0 -283
- package/tests/app.test.js +0 -17
- package/tests/authorizer.test.js +0 -301
- package/tests/bot.donothing.test.js +0 -30
- package/tests/bot.ok.test.js +0 -101
- package/tests/botcontext.test.js +0 -720
- package/tests/botdatastorage.test.js +0 -88
- package/tests/botfactory.provincebotfactory.test.js +0 -430
- package/tests/digester.test.js +0 -56
- package/tests/fixtures/bots.js +0 -27
- package/tests/fixtures/eventloggingbot.js +0 -57
- package/tests/fixtures/provincebotfactory.js +0 -53
- package/tests/httpsignature.test.js +0 -199
- package/tests/httpsignatureauthenticator.test.js +0 -463
- package/tests/index.test.js +0 -12
- package/tests/keystorage.test.js +0 -124
- package/tests/microsyntax.test.js +0 -123
- package/tests/objectcache.test.js +0 -133
- package/tests/objectstorage.test.js +0 -149
- package/tests/remotekeystorage.test.js +0 -78
- package/tests/routes.actor.test.js +0 -214
- package/tests/routes.collection.test.js +0 -310
- package/tests/routes.health.test.js +0 -41
- package/tests/routes.inbox.test.js +0 -216
- package/tests/routes.object.test.js +0 -525
- package/tests/routes.server.test.js +0 -69
- package/tests/routes.sharedinbox.test.js +0 -473
- package/tests/routes.webfinger.test.js +0 -68
- package/tests/urlformatter.test.js +0 -164
- package/tests/utils/digest.js +0 -7
- package/tests/utils/nock.js +0 -499
package/tests/index.test.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import { describe, it } from 'node:test'
|
|
3
|
-
describe('package exports', () => {
|
|
4
|
-
it('exposes Bot, BotFactory, default bots, and makeApp', async () => {
|
|
5
|
-
const { Bot, BotFactory, makeApp, DoNothingBot, OKBot } = await import('../lib/index.js')
|
|
6
|
-
assert.equal(typeof Bot, 'function')
|
|
7
|
-
assert.equal(typeof BotFactory, 'function')
|
|
8
|
-
assert.equal(typeof makeApp, 'function')
|
|
9
|
-
assert.equal(typeof OKBot, 'function')
|
|
10
|
-
assert.equal(typeof DoNothingBot, 'function')
|
|
11
|
-
})
|
|
12
|
-
})
|
package/tests/keystorage.test.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { describe, before, after, it } from 'node:test'
|
|
2
|
-
import { KeyStorage } from '../lib/keystorage.js'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { Sequelize } from 'sequelize'
|
|
5
|
-
import Logger from 'pino'
|
|
6
|
-
import { runMigrations } from '../lib/migrations/index.js'
|
|
7
|
-
|
|
8
|
-
describe('KeyStorage', async () => {
|
|
9
|
-
let connection = null
|
|
10
|
-
let storage = null
|
|
11
|
-
let logger = null
|
|
12
|
-
let firstPublicKey = null
|
|
13
|
-
let firstPrivateKey = null
|
|
14
|
-
let secondPublicKey = null
|
|
15
|
-
let secondPrivateKey = null
|
|
16
|
-
let firstSystemPublicKey = null
|
|
17
|
-
let firstSystemPrivateKey = null
|
|
18
|
-
let secondSystemPublicKey = null
|
|
19
|
-
let secondSystemPrivateKey = null
|
|
20
|
-
before(async () => {
|
|
21
|
-
connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
|
22
|
-
await connection.authenticate()
|
|
23
|
-
await runMigrations(connection)
|
|
24
|
-
logger = new Logger({
|
|
25
|
-
level: 'silent'
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
after(async () => {
|
|
29
|
-
await connection.close()
|
|
30
|
-
connection = null
|
|
31
|
-
logger = null
|
|
32
|
-
})
|
|
33
|
-
it('can initialize', async () => {
|
|
34
|
-
storage = new KeyStorage(connection, logger)
|
|
35
|
-
})
|
|
36
|
-
it('can get a public key', async () => {
|
|
37
|
-
firstPublicKey = await storage.getPublicKey('test1')
|
|
38
|
-
assert.ok(firstPublicKey)
|
|
39
|
-
assert.equal(typeof firstPublicKey, 'string')
|
|
40
|
-
assert.match(firstPublicKey, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
41
|
-
assert.match(firstPublicKey, /-----END PUBLIC KEY-----\n$/)
|
|
42
|
-
})
|
|
43
|
-
it('can get a public key again', async () => {
|
|
44
|
-
secondPublicKey = await storage.getPublicKey('test1')
|
|
45
|
-
assert.ok(secondPublicKey)
|
|
46
|
-
assert.equal(typeof secondPublicKey, 'string')
|
|
47
|
-
assert.match(secondPublicKey, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
48
|
-
assert.match(secondPublicKey, /-----END PUBLIC KEY-----\n$/)
|
|
49
|
-
assert.equal(firstPublicKey, secondPublicKey)
|
|
50
|
-
})
|
|
51
|
-
it('can get a private key after getting a public key', async () => {
|
|
52
|
-
const privateKey = await storage.getPrivateKey('test1')
|
|
53
|
-
assert.ok(privateKey)
|
|
54
|
-
assert.equal(typeof privateKey, 'string')
|
|
55
|
-
assert.match(privateKey, /^-----BEGIN PRIVATE KEY-----\n/)
|
|
56
|
-
assert.match(privateKey, /-----END PRIVATE KEY-----\n$/)
|
|
57
|
-
})
|
|
58
|
-
it('can get a private key', async () => {
|
|
59
|
-
firstPrivateKey = await storage.getPrivateKey('test2')
|
|
60
|
-
assert.ok(firstPrivateKey)
|
|
61
|
-
assert.equal(typeof firstPrivateKey, 'string')
|
|
62
|
-
assert.match(firstPrivateKey, /^-----BEGIN PRIVATE KEY-----\n/)
|
|
63
|
-
assert.match(firstPrivateKey, /-----END PRIVATE KEY-----\n$/)
|
|
64
|
-
})
|
|
65
|
-
it('can get a private key again', async () => {
|
|
66
|
-
secondPrivateKey = await storage.getPrivateKey('test2')
|
|
67
|
-
assert.ok(secondPrivateKey)
|
|
68
|
-
assert.equal(typeof secondPrivateKey, 'string')
|
|
69
|
-
assert.match(secondPrivateKey, /^-----BEGIN PRIVATE KEY-----\n/)
|
|
70
|
-
assert.match(secondPrivateKey, /-----END PRIVATE KEY-----\n$/)
|
|
71
|
-
assert.equal(firstPrivateKey, secondPrivateKey)
|
|
72
|
-
})
|
|
73
|
-
it('can get a public key after getting a private key', async () => {
|
|
74
|
-
const publicKey = await storage.getPublicKey('test2')
|
|
75
|
-
assert.ok(publicKey)
|
|
76
|
-
assert.equal(typeof publicKey, 'string')
|
|
77
|
-
assert.match(publicKey, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
78
|
-
assert.match(publicKey, /-----END PUBLIC KEY-----\n$/)
|
|
79
|
-
})
|
|
80
|
-
it('can get distinct public keys for distinct bots', async () => {
|
|
81
|
-
const publicKey = await storage.getPublicKey('test1')
|
|
82
|
-
const publicKey2 = await storage.getPublicKey('test2')
|
|
83
|
-
assert.ok(publicKey)
|
|
84
|
-
assert.ok(publicKey2)
|
|
85
|
-
assert.notEqual(publicKey, publicKey2)
|
|
86
|
-
})
|
|
87
|
-
it('can get distinct private keys for distinct bots', async () => {
|
|
88
|
-
const privateKey = await storage.getPrivateKey('test1')
|
|
89
|
-
const privateKey2 = await storage.getPrivateKey('test2')
|
|
90
|
-
assert.ok(privateKey)
|
|
91
|
-
assert.ok(privateKey2)
|
|
92
|
-
assert.notEqual(privateKey, privateKey2)
|
|
93
|
-
})
|
|
94
|
-
it('can get a system public key', async () => {
|
|
95
|
-
firstSystemPublicKey = await storage.getPublicKey(null)
|
|
96
|
-
assert.ok(firstSystemPublicKey)
|
|
97
|
-
assert.equal(typeof firstSystemPublicKey, 'string')
|
|
98
|
-
assert.match(firstSystemPublicKey, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
99
|
-
assert.match(firstSystemPublicKey, /-----END PUBLIC KEY-----\n$/)
|
|
100
|
-
})
|
|
101
|
-
it('can get a system public key again', async () => {
|
|
102
|
-
secondSystemPublicKey = await storage.getPublicKey(null)
|
|
103
|
-
assert.ok(secondSystemPublicKey)
|
|
104
|
-
assert.equal(typeof secondSystemPublicKey, 'string')
|
|
105
|
-
assert.match(secondSystemPublicKey, /^-----BEGIN PUBLIC KEY-----\n/)
|
|
106
|
-
assert.match(secondSystemPublicKey, /-----END PUBLIC KEY-----\n$/)
|
|
107
|
-
assert.equal(firstSystemPublicKey, secondSystemPublicKey)
|
|
108
|
-
})
|
|
109
|
-
it('can get a system private key', async () => {
|
|
110
|
-
firstSystemPrivateKey = await storage.getPrivateKey(null)
|
|
111
|
-
assert.ok(firstSystemPrivateKey)
|
|
112
|
-
assert.equal(typeof firstSystemPrivateKey, 'string')
|
|
113
|
-
assert.match(firstSystemPrivateKey, /^-----BEGIN PRIVATE KEY-----\n/)
|
|
114
|
-
assert.match(firstSystemPrivateKey, /-----END PRIVATE KEY-----\n$/)
|
|
115
|
-
})
|
|
116
|
-
it('can get a system private key again', async () => {
|
|
117
|
-
secondSystemPrivateKey = await storage.getPrivateKey(null)
|
|
118
|
-
assert.ok(secondSystemPrivateKey)
|
|
119
|
-
assert.equal(typeof secondSystemPrivateKey, 'string')
|
|
120
|
-
assert.match(secondSystemPrivateKey, /^-----BEGIN PRIVATE KEY-----\n/)
|
|
121
|
-
assert.match(secondSystemPrivateKey, /-----END PRIVATE KEY-----\n$/)
|
|
122
|
-
assert.equal(firstSystemPrivateKey, secondSystemPrivateKey)
|
|
123
|
-
})
|
|
124
|
-
})
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import { Sequelize } from 'sequelize'
|
|
4
|
-
import { Transformer } from '../lib/microsyntax.js'
|
|
5
|
-
import { UrlFormatter } from '../lib/urlformatter.js'
|
|
6
|
-
import { KeyStorage } from '../lib/keystorage.js'
|
|
7
|
-
import { ActivityPubClient } from '../lib/activitypubclient.js'
|
|
8
|
-
import { nockSetup } from './utils/nock.js'
|
|
9
|
-
import { HTTPSignature } from '../lib/httpsignature.js'
|
|
10
|
-
import Logger from 'pino'
|
|
11
|
-
import { Digester } from '../lib/digester.js'
|
|
12
|
-
import { runMigrations } from '../lib/migrations/index.js'
|
|
13
|
-
|
|
14
|
-
const AS2 = 'https://www.w3.org/ns/activitystreams#'
|
|
15
|
-
|
|
16
|
-
describe('microsyntax', async () => {
|
|
17
|
-
const tagNamespace = 'https://tags.example/tag/'
|
|
18
|
-
const origin = 'https://activitypubbot.example'
|
|
19
|
-
|
|
20
|
-
nockSetup('social.example')
|
|
21
|
-
|
|
22
|
-
const logger = Logger({
|
|
23
|
-
level: 'silent'
|
|
24
|
-
})
|
|
25
|
-
const digester = new Digester(logger)
|
|
26
|
-
const connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
|
27
|
-
await connection.authenticate()
|
|
28
|
-
await runMigrations(connection)
|
|
29
|
-
const keyStorage = new KeyStorage(connection, logger)
|
|
30
|
-
const formatter = new UrlFormatter(origin)
|
|
31
|
-
const signer = new HTTPSignature(logger)
|
|
32
|
-
const client = new ActivityPubClient(keyStorage, formatter, signer, digester, logger)
|
|
33
|
-
const transformer = new Transformer(tagNamespace, client)
|
|
34
|
-
|
|
35
|
-
it('has transformer', () => {
|
|
36
|
-
assert.ok(transformer)
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
describe('transform tagless text', async () => {
|
|
40
|
-
const text = 'Hello, world!'
|
|
41
|
-
const { html } = await transformer.transform(text)
|
|
42
|
-
it('has output', () => {
|
|
43
|
-
assert.ok(html)
|
|
44
|
-
})
|
|
45
|
-
it('is the same as input', () => {
|
|
46
|
-
assert.equal(html, `<p>${text}</p>`)
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('transform hashtag', async () => {
|
|
51
|
-
const text = 'Hello, World! #greeting'
|
|
52
|
-
const { html, tag } = await transformer.transform(text)
|
|
53
|
-
it('has html output', () => {
|
|
54
|
-
assert.ok(html)
|
|
55
|
-
})
|
|
56
|
-
it('has tag', () => {
|
|
57
|
-
assert.ok(tag)
|
|
58
|
-
})
|
|
59
|
-
it('has correct html', () => {
|
|
60
|
-
assert.equal(html, '<p>Hello, World! <a href="https://tags.example/tag/greeting">#greeting</a></p>')
|
|
61
|
-
})
|
|
62
|
-
it('has correct tag', () => {
|
|
63
|
-
assert.equal(tag.length, 1)
|
|
64
|
-
assert.equal(tag[0].type, AS2 + 'Hashtag')
|
|
65
|
-
assert.equal(tag[0].name, '#greeting')
|
|
66
|
-
assert.equal(tag[0].href, 'https://tags.example/tag/greeting')
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
describe('transform url', async () => {
|
|
71
|
-
const text = 'Please visit https://example.com for more information.'
|
|
72
|
-
const { html, tag } = await transformer.transform(text)
|
|
73
|
-
it('has html output', () => {
|
|
74
|
-
assert.ok(html)
|
|
75
|
-
})
|
|
76
|
-
it('has tag', () => {
|
|
77
|
-
assert.ok(tag)
|
|
78
|
-
})
|
|
79
|
-
it('has correct html', () => {
|
|
80
|
-
assert.equal(html, '<p>Please visit <a href="https://example.com">https://example.com</a> for more information.</p>')
|
|
81
|
-
})
|
|
82
|
-
it('has correct tag', () => {
|
|
83
|
-
assert.equal(tag.length, 0)
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
describe('transform url with fragment', async () => {
|
|
88
|
-
const text = 'Please visit https://example.com#fragment for more information.'
|
|
89
|
-
const { html, tag } = await transformer.transform(text)
|
|
90
|
-
it('has html output', () => {
|
|
91
|
-
assert.ok(html)
|
|
92
|
-
})
|
|
93
|
-
it('has tag', () => {
|
|
94
|
-
assert.ok(tag)
|
|
95
|
-
})
|
|
96
|
-
it('has correct html', () => {
|
|
97
|
-
assert.equal(html, '<p>Please visit <a href="https://example.com#fragment">https://example.com#fragment</a> for more information.</p>')
|
|
98
|
-
})
|
|
99
|
-
it('has correct tag', () => {
|
|
100
|
-
assert.equal(tag.length, 0)
|
|
101
|
-
})
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
describe('transform full mention', async () => {
|
|
105
|
-
const text = 'Hello, @world@social.example !'
|
|
106
|
-
const { html, tag } = await transformer.transform(text)
|
|
107
|
-
it('has html output', () => {
|
|
108
|
-
assert.ok(html)
|
|
109
|
-
})
|
|
110
|
-
it('has tag', () => {
|
|
111
|
-
assert.ok(tag)
|
|
112
|
-
})
|
|
113
|
-
it('has correct html', () => {
|
|
114
|
-
assert.equal(html, '<p>Hello, <a href="https://social.example/profile/world">@world@social.example</a> !</p>')
|
|
115
|
-
})
|
|
116
|
-
it('has correct tag', () => {
|
|
117
|
-
assert.equal(tag.length, 1)
|
|
118
|
-
assert.equal(tag[0].type, 'Mention')
|
|
119
|
-
assert.equal(tag[0].name, '@world@social.example')
|
|
120
|
-
assert.equal(tag[0].href, 'https://social.example/profile/world')
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
})
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import { ObjectCache } from '../lib/objectcache.js'
|
|
3
|
-
import assert from 'node:assert/strict'
|
|
4
|
-
import as2 from '../lib/activitystreams.js'
|
|
5
|
-
|
|
6
|
-
describe('ObjectCache', async () => {
|
|
7
|
-
let cache = null
|
|
8
|
-
const longTTL = 3600 * 1000
|
|
9
|
-
const shortTTL = 300 * 1000
|
|
10
|
-
const maxItems = 1000
|
|
11
|
-
const makeObject = (num) =>
|
|
12
|
-
as2.import({
|
|
13
|
-
id: `https://example.com/${num}`,
|
|
14
|
-
name: `Object ${num}`,
|
|
15
|
-
type: 'Object',
|
|
16
|
-
attributedTo: `https://example.com/user${num}`,
|
|
17
|
-
to: 'https://www.w3.org/ns/activitystreams#Public'
|
|
18
|
-
})
|
|
19
|
-
const makeCollection = (num) =>
|
|
20
|
-
as2.import({
|
|
21
|
-
id: `https://example.com/collection${num}`,
|
|
22
|
-
type: 'Collection',
|
|
23
|
-
name: `Collection ${num}`,
|
|
24
|
-
totalItems: 1
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
const object1 = await makeObject(1)
|
|
28
|
-
const object2 = await makeObject(2)
|
|
29
|
-
const object3 = await makeObject(3)
|
|
30
|
-
const object4 = await makeObject(4)
|
|
31
|
-
const object5 = await makeObject(5)
|
|
32
|
-
const badid = 'https://example.com/badid'
|
|
33
|
-
const badcoll = 'https://example.com/badcoll'
|
|
34
|
-
const collection1 = await makeCollection(1)
|
|
35
|
-
const collection2 = await makeCollection(2)
|
|
36
|
-
const collection3 = await makeCollection(3)
|
|
37
|
-
|
|
38
|
-
it('should be a class', async () => {
|
|
39
|
-
assert.strictEqual(typeof ObjectCache, 'function')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('can be instantiated', async () => {
|
|
43
|
-
cache = new ObjectCache({ longTTL, shortTTL, maxItems })
|
|
44
|
-
assert.strictEqual(typeof cache, 'object')
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('can be initialized', async () => {
|
|
48
|
-
try {
|
|
49
|
-
await cache.initialize()
|
|
50
|
-
assert.ok(true)
|
|
51
|
-
} catch (error) {
|
|
52
|
-
assert.fail(error)
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('returns undefined if not found', async () => {
|
|
57
|
-
try {
|
|
58
|
-
const value = await cache.get(badid)
|
|
59
|
-
assert.strictEqual(value, undefined)
|
|
60
|
-
} catch (error) {
|
|
61
|
-
assert.fail(error)
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('can save', async () => {
|
|
66
|
-
try {
|
|
67
|
-
await cache.save(object1)
|
|
68
|
-
const dupe = await cache.get(object1.id)
|
|
69
|
-
assert.strictEqual(dupe.id, object1.id)
|
|
70
|
-
} catch (error) {
|
|
71
|
-
assert.fail(error)
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('can saveReceived', async () => {
|
|
76
|
-
try {
|
|
77
|
-
await cache.saveReceived(object2)
|
|
78
|
-
const dupe = await cache.get(object2.id)
|
|
79
|
-
assert.strictEqual(dupe.id, object2.id)
|
|
80
|
-
} catch (error) {
|
|
81
|
-
assert.fail(error)
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('can clear', async () => {
|
|
86
|
-
try {
|
|
87
|
-
await cache.save(object3)
|
|
88
|
-
await cache.clear(object3)
|
|
89
|
-
const dupe = await cache.get(object3.id)
|
|
90
|
-
assert.strictEqual(dupe, undefined)
|
|
91
|
-
} catch (error) {
|
|
92
|
-
assert.fail(error)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('fails membership for unknown collection', async () => {
|
|
97
|
-
try {
|
|
98
|
-
const flag = await cache.isMember(collection3, badid)
|
|
99
|
-
assert.strictEqual(flag, undefined)
|
|
100
|
-
} catch (error) {
|
|
101
|
-
assert.fail(error)
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('fails membership for unknown object', async () => {
|
|
106
|
-
try {
|
|
107
|
-
const flag = await cache.isMember(badcoll, object4)
|
|
108
|
-
assert.strictEqual(flag, undefined)
|
|
109
|
-
} catch (error) {
|
|
110
|
-
assert.fail(error)
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('can saveMembership', async () => {
|
|
115
|
-
try {
|
|
116
|
-
await cache.saveMembership(collection1, object4)
|
|
117
|
-
const flag = await cache.isMember(collection1, object4)
|
|
118
|
-
assert.ok(flag)
|
|
119
|
-
} catch (error) {
|
|
120
|
-
assert.fail(error)
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('can saveMembershipReceived', async () => {
|
|
125
|
-
try {
|
|
126
|
-
await cache.saveMembershipReceived(collection2, object5)
|
|
127
|
-
const flag = await cache.isMember(collection2, object5)
|
|
128
|
-
assert.ok(flag)
|
|
129
|
-
} catch (error) {
|
|
130
|
-
assert.fail(error)
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
})
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { describe, it, before, after } from 'node:test'
|
|
2
|
-
import as2 from '../lib/activitystreams.js'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { ObjectStorage, NoSuchObjectError } from '../lib/objectstorage.js'
|
|
5
|
-
import { Sequelize } from 'sequelize'
|
|
6
|
-
import { runMigrations } from '../lib/migrations/index.js'
|
|
7
|
-
|
|
8
|
-
describe('ObjectStorage', async () => {
|
|
9
|
-
let doc = null
|
|
10
|
-
let doc2 = null
|
|
11
|
-
let doc3 = null
|
|
12
|
-
let connection = null
|
|
13
|
-
let storage = null
|
|
14
|
-
before(async () => {
|
|
15
|
-
doc = await as2.import({
|
|
16
|
-
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
17
|
-
id: 'https://social.example/users/test/note/1',
|
|
18
|
-
type: 'Note',
|
|
19
|
-
name: 'test',
|
|
20
|
-
content: 'test'
|
|
21
|
-
})
|
|
22
|
-
doc2 = await as2.import({
|
|
23
|
-
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
24
|
-
id: 'https://social.example/users/test/note/2',
|
|
25
|
-
type: 'Note',
|
|
26
|
-
name: 'test',
|
|
27
|
-
content: 'test',
|
|
28
|
-
inReplyTo: doc.id
|
|
29
|
-
})
|
|
30
|
-
doc3 = await as2.import({
|
|
31
|
-
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
32
|
-
id: 'https://social.example/users/test/note/3',
|
|
33
|
-
type: 'Note',
|
|
34
|
-
name: 'test',
|
|
35
|
-
content: 'test'
|
|
36
|
-
})
|
|
37
|
-
connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
|
38
|
-
await connection.authenticate()
|
|
39
|
-
await runMigrations(connection)
|
|
40
|
-
})
|
|
41
|
-
after(async () => {
|
|
42
|
-
await connection.close()
|
|
43
|
-
})
|
|
44
|
-
it('can initialize', async () => {
|
|
45
|
-
storage = new ObjectStorage(connection)
|
|
46
|
-
})
|
|
47
|
-
it('can create a new object', async () => {
|
|
48
|
-
await storage.create(doc)
|
|
49
|
-
})
|
|
50
|
-
it('can read a created object', async () => {
|
|
51
|
-
await storage.read(doc.id)
|
|
52
|
-
})
|
|
53
|
-
it('can update a created object', async () => {
|
|
54
|
-
const doc2 = await as2.import({
|
|
55
|
-
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
56
|
-
id: 'https://social.example/users/test/note/1',
|
|
57
|
-
type: 'Note',
|
|
58
|
-
name: 'test2',
|
|
59
|
-
content: 'test2'
|
|
60
|
-
})
|
|
61
|
-
await storage.update(doc2)
|
|
62
|
-
const read = await storage.read(doc2.id)
|
|
63
|
-
assert.equal(read.name.get(), 'test2')
|
|
64
|
-
})
|
|
65
|
-
it('can delete a created object', async () => {
|
|
66
|
-
await storage.delete(doc)
|
|
67
|
-
try {
|
|
68
|
-
await storage.read(doc.id)
|
|
69
|
-
assert.fail('should not be able to read deleted object')
|
|
70
|
-
} catch (err) {
|
|
71
|
-
assert.ok(err instanceof NoSuchObjectError)
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
it('can get a collection', async () => {
|
|
75
|
-
const collection = await storage.getCollection(doc.id, 'replies')
|
|
76
|
-
assert.equal(typeof (collection), 'object')
|
|
77
|
-
assert.equal(typeof (collection.id), 'string')
|
|
78
|
-
assert.equal(collection.id, `${doc.id}/replies`)
|
|
79
|
-
assert.equal(collection.type, 'https://www.w3.org/ns/activitystreams#OrderedCollection')
|
|
80
|
-
assert.equal(collection.totalItems, 0)
|
|
81
|
-
assert.equal(collection.first.id, `${doc.id}/replies/1`)
|
|
82
|
-
assert.equal(collection.last.id, `${doc.id}/replies/1`)
|
|
83
|
-
})
|
|
84
|
-
it('can get a collection page', async () => {
|
|
85
|
-
const page = await storage.getCollectionPage(doc.id, 'replies', 1)
|
|
86
|
-
assert.equal(typeof page, 'object')
|
|
87
|
-
assert.equal(page.id, `${doc.id}/replies/1`)
|
|
88
|
-
assert.equal(page.type, 'https://www.w3.org/ns/activitystreams#OrderedCollectionPage')
|
|
89
|
-
assert.equal(page.partOf.id, `${doc.id}/replies`)
|
|
90
|
-
assert.ok(!page.next)
|
|
91
|
-
assert.ok(!page.prev)
|
|
92
|
-
assert.ok(!page.items)
|
|
93
|
-
})
|
|
94
|
-
it('can add to a collection', async () => {
|
|
95
|
-
await storage.addToCollection(doc.id, 'replies', doc2)
|
|
96
|
-
const page = await storage.getCollectionPage(doc.id, 'replies', 1)
|
|
97
|
-
assert.ok(Array.from(page.items).find(item => item.id === doc2.id))
|
|
98
|
-
})
|
|
99
|
-
it('can check collection membership', async () => {
|
|
100
|
-
assert.strictEqual(true, await storage.isInCollection(doc.id, 'replies', doc2))
|
|
101
|
-
assert.strictEqual(false, await storage.isInCollection(doc.id, 'replies', doc3))
|
|
102
|
-
})
|
|
103
|
-
it('can remove from a collection', async () => {
|
|
104
|
-
await storage.removeFromCollection(doc.id, 'replies', doc2)
|
|
105
|
-
const page = await storage.getCollectionPage(doc.id, 'replies', 1)
|
|
106
|
-
assert.ok(!page.items)
|
|
107
|
-
})
|
|
108
|
-
it('can add many items to a collection', async () => {
|
|
109
|
-
for (let i = 3; i < 103; i++) {
|
|
110
|
-
const reply = await as2.import({
|
|
111
|
-
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
112
|
-
id: `https://social.example/users/test/note/${i}`,
|
|
113
|
-
type: 'Note',
|
|
114
|
-
name: 'test',
|
|
115
|
-
content: 'test',
|
|
116
|
-
inReplyTo: doc.id
|
|
117
|
-
})
|
|
118
|
-
await storage.addToCollection(doc.id, 'replies', reply)
|
|
119
|
-
}
|
|
120
|
-
const collection = await storage.getCollection(doc.id, 'replies')
|
|
121
|
-
assert.equal(collection.totalItems, 100)
|
|
122
|
-
assert.equal(collection.first.id, `${doc.id}/replies/5`)
|
|
123
|
-
assert.equal(collection.last.id, `${doc.id}/replies/1`)
|
|
124
|
-
const page = await storage.getCollectionPage(doc.id, 'replies', 3)
|
|
125
|
-
assert.ok(page.next)
|
|
126
|
-
// assert.ok(page.prev)
|
|
127
|
-
assert.ok(page.items)
|
|
128
|
-
const items = Array.from(page.items)
|
|
129
|
-
assert.equal(items.length, 20)
|
|
130
|
-
for (let i = 0; i < items.length; i++) {
|
|
131
|
-
assert.ok(items[i])
|
|
132
|
-
for (let j = i + 1; j < items.length; j++) {
|
|
133
|
-
assert.ok(items[j])
|
|
134
|
-
assert.ok(
|
|
135
|
-
items[i].id > items[j].id,
|
|
136
|
-
`item ${i} (${items[i].id}) <= item ${j} (${items[j].id})`
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
it('can iterate over a collection', async () => {
|
|
142
|
-
const seen = new Set()
|
|
143
|
-
for await (const item of storage.items(doc.id, 'replies')) {
|
|
144
|
-
assert.ok(!(item.id in seen))
|
|
145
|
-
seen.add(item.id)
|
|
146
|
-
}
|
|
147
|
-
assert.strictEqual(seen.size, 100)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { describe, before, after, it } from 'node:test'
|
|
2
|
-
import { RemoteKeyStorage } from '../lib/remotekeystorage.js'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { Sequelize } from 'sequelize'
|
|
5
|
-
import { KeyStorage } from '../lib/keystorage.js'
|
|
6
|
-
import { UrlFormatter } from '../lib/urlformatter.js'
|
|
7
|
-
import { ActivityPubClient } from '../lib/activitypubclient.js'
|
|
8
|
-
import { nockSetup, nockFormat, getPublicKey, nockKeyRotate } from './utils/nock.js'
|
|
9
|
-
import { HTTPSignature } from '../lib/httpsignature.js'
|
|
10
|
-
import Logger from 'pino'
|
|
11
|
-
import { Digester } from '../lib/digester.js'
|
|
12
|
-
import { runMigrations } from '../lib/migrations/index.js'
|
|
13
|
-
|
|
14
|
-
describe('RemoteKeyStorage', async () => {
|
|
15
|
-
const host = 'activitypubbot.example'
|
|
16
|
-
const remoteHost = 'social.example'
|
|
17
|
-
const origin = `https://${host}`
|
|
18
|
-
let connection = null
|
|
19
|
-
let remoteKeyStorage = null
|
|
20
|
-
let client = null
|
|
21
|
-
let logger = null
|
|
22
|
-
before(async () => {
|
|
23
|
-
logger = Logger({
|
|
24
|
-
level: 'silent'
|
|
25
|
-
})
|
|
26
|
-
connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
|
|
27
|
-
await connection.authenticate()
|
|
28
|
-
await runMigrations(connection)
|
|
29
|
-
const keyStorage = new KeyStorage(connection, logger)
|
|
30
|
-
const formatter = new UrlFormatter(origin)
|
|
31
|
-
const digester = new Digester(logger)
|
|
32
|
-
const signer = new HTTPSignature(logger)
|
|
33
|
-
client = new ActivityPubClient(keyStorage, formatter, signer, digester, logger)
|
|
34
|
-
nockSetup(remoteHost)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
after(async () => {
|
|
38
|
-
await connection.close()
|
|
39
|
-
logger = null
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('can initialize', async () => {
|
|
43
|
-
remoteKeyStorage = new RemoteKeyStorage(client, connection, logger)
|
|
44
|
-
assert.ok(remoteKeyStorage)
|
|
45
|
-
assert.ok(true)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('can get a remote public key', async () => {
|
|
49
|
-
const username = 'test'
|
|
50
|
-
const domain = remoteHost
|
|
51
|
-
const id = nockFormat({ username, key: true, domain })
|
|
52
|
-
const publicKey = await getPublicKey(username, domain)
|
|
53
|
-
const remote = await remoteKeyStorage.getPublicKey(id)
|
|
54
|
-
assert.equal(remote.publicKeyPem, publicKey)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('can get the same remote public key twice', async () => {
|
|
58
|
-
const username = 'test'
|
|
59
|
-
const domain = remoteHost
|
|
60
|
-
const id = nockFormat({ username, key: true, domain })
|
|
61
|
-
const publicKey = await getPublicKey(username, domain)
|
|
62
|
-
const remote = await remoteKeyStorage.getPublicKey(id)
|
|
63
|
-
assert.equal(remote.publicKeyPem, publicKey)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('can get the right public key after key rotation', async () => {
|
|
67
|
-
const username = 'test'
|
|
68
|
-
const domain = remoteHost
|
|
69
|
-
const id = nockFormat({ username, key: true, domain })
|
|
70
|
-
const publicKey = await getPublicKey(username, domain)
|
|
71
|
-
const remote = await remoteKeyStorage.getPublicKey(id)
|
|
72
|
-
assert.equal(remote.publicKeyPem, publicKey)
|
|
73
|
-
await nockKeyRotate(username)
|
|
74
|
-
const publicKey2 = await getPublicKey(username, domain)
|
|
75
|
-
const remote2 = await remoteKeyStorage.getPublicKey(id, false)
|
|
76
|
-
assert.equal(remote2.publicKeyPem, publicKey2)
|
|
77
|
-
})
|
|
78
|
-
})
|