-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
127 lines (102 loc) · 3.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* eslint-disable brace-style */
const get = require('lodash.get')
const isString = (t) => (typeof t === 'string')
const NotBothError = () => new Error(
'recps-guard: should not have recps && allowPublic, check your code'
)
const NotAllowedTypeError = (type) => new Error(
`recps-guard: public messages of type "${type}" not allowed`
)
let warnings = 0
module.exports = {
name: 'recpsGuard',
version: require('./package.json').version,
manifest: {
allowedTypes: 'async'
},
init (ssb, config) {
const allowedTypes = getAllowedTypes(ssb, config)
const isAllowedType = (type) => allowedTypes.has(type)
function publishHook (publish, args) {
const [input, cb] = args
const modernAllow = input.allowPublic === true
const legacyAllow = get(input, ['options', 'allowPublic']) === true
if (legacyAllow && warnings < 5) {
console.trace('input.options.allowPublic is deprecated, please use input.allowPublic')
warnings++
}
const isExplictAllow = (modernAllow || legacyAllow)
if (isExplictAllow) {
const content = input.content
if (hasRecps(content)) cb(NotBothError())
else publish(content, cb)
}
else {
const content = input
const isAllowed = (
isString(content) || // already encrypted
hasRecps(content) ||
isAllowedType(content.type)
)
if (isAllowed) publish(content, cb)
else cb(NotAllowedTypeError(content.type))
}
}
function createHook (create, args) {
const [input, cb] = args
if (input.allowPublic === true) {
if (hasRecps(input.content)) return cb(NotBothError())
return create(input, cb)
}
else {
const content = input.content
const isAllowed = (
isString(content) || // already encrypted
input.encryptionFormat || // signed up for encryption
hasRecps(content) ||
isAllowedType(content.type)
)
if (isAllowed) create(input, cb)
else cb(NotAllowedTypeError(content.type))
}
}
if (ssb.publish) {
ssb.publish.hook(publishHook)
ssb.publish.hook = () => {
throw new Error('ssb-recps-guard must be the last to hook ssb.publish')
// NOTE because of the last hook get run first we need to guarentee
// that no other hooks on publish occured after our, otherwise we cannot
// guarentee other hooks do not bypass the guard
}
}
if (ssb.db && ssb.db.create) {
ssb.db.create.hook(createHook)
ssb.db.create.hook = () => {
throw new Error('ssb-recps-guard must be the last to hook ssb.db.create')
// NOTE because of the last hook get run first we need to guarentee
// that no other hooks on create occured after our, otherwise we cannot
// guarentee other hooks do not bypass the guard
}
}
/* API */
return {
allowedTypes () {
return Array.from(allowedTypes).sort()
}
}
}
}
function getAllowedTypes (ssb, config) {
const types = get(config, 'recpsGuard.allowedTypes', [])
if (!types.every(isString)) {
ssb.close() // weird, but if we don't do this, tests hang
throw new Error('recps-guard: expects allowedTypes to be an Array of Strings')
}
return new Set(types)
}
function hasRecps (content) {
if (!content.recps) return false
if (!Array.isArray(content.recps)) return false
if (content.recps.length === 0) return false
return true
}