Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 92771e5

Browse files
committed
broadcasts, more user validation
1 parent 51faa5a commit 92771e5

File tree

9 files changed

+1646
-2
lines changed

9 files changed

+1646
-2
lines changed

package-lock.json

+1,517
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
"author": "",
1010
"license": "ISC",
1111
"dependencies": {
12+
"@blurtfoundation/blurtjs": "^1.0.0",
13+
"@hiveio/hive-js": "^2.0.4",
1214
"body-parser": "^1.20.0",
15+
"javalon": "^1.0.34",
1316
"mongodb": "^4.5.0"
1417
}
1518
}

src/actions.js

+28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ let actions = {
55
new: async (user,network,operation,operationNetwork,scheduled) => {
66
if (!validator.validate(operationNetwork,operation))
77
return { error: 'operation validation failed' }
8+
else if (!validator.general.positiveInteger(scheduled) || scheduled < new Date().getTime())
9+
return { error: 'scheduled timestamp must be in the future' }
810
let newDoc
911
try {
1012
newDoc = await mongo.db.collection('operations').insertOne({
@@ -22,6 +24,20 @@ let actions = {
2224
edit: async (user,network,id,updatedOperation,updatedOperationNetwork,scheduled) => {
2325
if (!validator.validate(updatedOperationNetwork,updatedOperation))
2426
return { error: 'updated operation validation failed' }
27+
else if (!validator.general.positiveInteger(scheduled) || scheduled < new Date().getTime())
28+
return { error: 'scheduled timestamp must be in the future' }
29+
let existing
30+
try {
31+
existing = await mongo.db.collection('operations').findOne({ _id: new mongo.objectId(id) })
32+
} catch (e) {
33+
return { error: e.toString() }
34+
}
35+
if (!existing)
36+
return { error: 'operation id does not exist' }
37+
else if (existing.tx || existing.error)
38+
return { error: 'cannot edit operations that have already been broadcasted' }
39+
else if (existing.user !== user || existing.network !== network)
40+
return { error: 'operation isn\'t yours to edit' }
2541
let update = { $set: {}}
2642
if (updatedOperation)
2743
update.$set.operation = updatedOperation
@@ -35,6 +51,16 @@ let actions = {
3551
return { result: { ok: 1 } }
3652
},
3753
delete: async (user,network,id) => {
54+
let existing
55+
try {
56+
existing = await mongo.db.collection('operations').findOne({ _id: new mongo.objectId(id) })
57+
} catch (e) {
58+
return { error: e.toString() }
59+
}
60+
if (!existing)
61+
return { error: 'operation id does not exist already' }
62+
else if (existing.user !== user || existing.network !== network)
63+
return { error: 'operation isn\'t yours to delete' }
3864
try {
3965
await mongo.db.collection('operations').deleteOne({ _id: new mongo.objectId(id) })
4066
} catch (e) {
@@ -49,6 +75,8 @@ let actions = {
4975
} catch (e) {
5076
return { error: e.toString() }
5177
}
78+
if (result.user !== user || result.network !== network)
79+
return { error: 'operation isn\'t yours to look at' }
5280
return { result: result }
5381
},
5482
list: async (user,network) => {

src/api.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const Parser = require('body-parser')
22
const mongo = require('./mongo')
33
const actions = require('./actions')
4+
const runner = require('./runner')
45
const config = require('./config')
56

67
let api = {
@@ -10,6 +11,7 @@ let api = {
1011
init: async (app, appConfig = {}, mongoClientDb = null, authenticator = null) => {
1112
config.init(appConfig)
1213
await mongo.init(mongoClientDb)
14+
runner.init()
1315

1416
if (typeof authenticator === 'function')
1517
api.authenticator = authenticator

src/broadcast.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const hive = require('@hiveio/hive-js')
2+
const blurt = require('@blurtfoundation/blurtjs')
3+
const avalon = require('javalon')
4+
const { config } = require('./config')
5+
6+
let broadcast = {
7+
init: (apis) => {
8+
if (apis.hive)
9+
hive.api.setOptions({ url: apis.hive, useAppbaseApi: true })
10+
if (apis.blurt)
11+
blurt.api.setOptions({ url: apis.blurt, useAppbaseApi: true })
12+
if (apis.avalon)
13+
avalon.init({ api: apis.avalon })
14+
},
15+
hive: (operation) => {
16+
return new Promise((rs,rj) => {
17+
if (!config.wifs.hive)
18+
return rj('No Wif')
19+
hive.broadcast.send({ extensions: [], operations: operation },[config.wifs.hive],(e,result) => {
20+
if (e)
21+
rj(e.toString())
22+
else
23+
rs(result.id)
24+
})
25+
})
26+
},
27+
blurt: (operation) => {
28+
return new Promise((rs,rj) => {
29+
if (!config.wifs.blurt)
30+
return rj('No Wif')
31+
blurt.broadcast.send({ extensions: [], operations: operation },[config.wifs.blurt],(e,result) => {
32+
if (e)
33+
rj(e.toString())
34+
else
35+
rs(result.id)
36+
})
37+
})
38+
},
39+
avalon: (operation) => {
40+
return new Promise((rs,rj) => {
41+
if (!config.wifs.avalon)
42+
return rj('No Wif')
43+
avalon.sendRawTransaction(avalon.signMultisig([config.wifs.avalon],operation.sender,operation),(e) => {
44+
if (e)
45+
rj(e.error)
46+
else
47+
rs(operation.hash)
48+
})
49+
})
50+
}
51+
}
52+
53+
module.exports = broadcast

src/config.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ let config = {
66
mongodbUrl: 'mongodb://localhost:27017',
77
mongodbName: 'olisc',
88
apiNamespace: '/olisc',
9+
runInterval: 300000,
10+
rpcs: {},
911
wifs: {}
1012
}
1113
}

src/runner.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const mongo = require('./mongo')
2+
const broadcast = require('./broadcast')
3+
const { config } = require('./config')
4+
5+
let runner = {
6+
init: () => {
7+
broadcast.init(config.rpcs)
8+
runner.scheduleNext()
9+
},
10+
scheduleNext: () => {
11+
let nextInterval = Math.ceil(new Date().getTime() / config.runInterval) * config.runInterval
12+
setTimeout(async () => {
13+
await runner.run()
14+
runner.scheduleNext()
15+
}, nextInterval - new Date().getTime())
16+
},
17+
run: async () => {
18+
let pendingOps = await mongo.db.collection('operations').find({ $and: [
19+
{ scheduled: { $lte: new Date().getTime() }},
20+
{ error: { $exists: false }},
21+
{ tx: { $exists: false }}
22+
]}).toArray()
23+
for (let op in pendingOps)
24+
if (broadcast[pendingOps[op].operationNetwork]) {
25+
let txhash
26+
try {
27+
txhash = await broadcast[pendingOps[op].operationNetwork](pendingOps[op].operation)
28+
} catch (e) {
29+
mongo.db.collection('operations').updateOne({ _id: pendingOps[op]._id }, { $set: { error: e } }).then(() => {}).catch(() => {})
30+
}
31+
mongo.db.collection('operations').updateOne({ _id: pendingOps[op]._id }, { $set: { tx: txhash } }).then(() => {}).catch(() => {})
32+
}
33+
}
34+
}
35+
36+
module.exports = runner

src/validator/hive.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let specificTypes = {
2626
return true
2727
},
2828
arrayOfUsernames: (val) => {
29-
if (!generalValidator.arrayOfStrings(val))
29+
if (!general.arrayOfStrings(val))
3030
return false
3131
for (let i in val)
3232
if (!specificTypes.username(val[i]))

src/validator/index.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const general = require('./general')
2+
13
let networkValidators = {
24
avalon: require('./avalon'),
35
blurt: require('./blurt'),
@@ -9,5 +11,6 @@ module.exports = {
911
if (!networkValidators[network])
1012
return false
1113
return networkValidators[network].validate(op)
12-
}
14+
},
15+
general
1316
}

0 commit comments

Comments
 (0)