Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ node_modules
# DAppNodeSDK release directories
build_*
/docker.tar.gz

.env
web_services/foxx/*.zip
4 changes: 4 additions & 0 deletions web_services/foxx/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ARANGO_SERVER=http://localhost:8529
ARANGO_DATABASE=
ARANGO_USERNAME=
ARANGO_PASSWORD=
Binary file removed web_services/foxx/apply5.zip
Binary file not shown.
108 changes: 108 additions & 0 deletions web_services/foxx/apply5/apply.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"use strict";
const createRouter = require("@arangodb/foxx/router");
const joi = require("joi");
const { db: arango, ArangoError } = require("@arangodb");
const nacl = require("tweetnacl");
const db = require("./db");
const operations = require("./operations");
const schemas = require("./schemas");
const errors = require("./errors");

const router = createRouter();
module.context.use(router);
const operationsHashesColl = arango._collection("operationsHashes");

const handlers = {
operationsPut: function (req, res) {
const op = req.body;
const hash = req.param("hash");
op.hash = hash;
try {
// decrypt first to use the original hash for querying operationsHashesColl
if (op.name == "Link ContextId") {
operations.decrypt(op);
}
if (operationsHashesColl.exists(op.hash)) {
throw new errors.OperationAppliedBeforeError(op.hash);
}
operations.verify(op);
op.result = operations.apply(op);
op.state = "applied";
operationsHashesColl.insert({ _key: op.hash });
if (op.name == "Link ContextId") {
operations.encrypt(op);
}
} catch (e) {
op.state = "failed";
if (e instanceof ArangoError) {
e.arangoErrorNum = e.errorNum;
e.errorNum = errors.ARANGO_ERROR;
}
op.result = {
message: e.message || e,
stack: !(e instanceof errors.BrightIDError) ? e.stack : undefined,
errorNum: e.errorNum,
arangoErrorNum: e.arangoErrorNum,
};
}
db.upsertOperation(op);
res.send({ success: true, state: op.state, result: op.result });
},
};

// add blockTime to operation schema
schemas.schemas.operation = joi
.alternatives()
.try(
Object.values(schemas.operations).map((op) => {
op.blockTime = joi
.number()
.required()
.description("milliseconds since epoch when the block was created");
return joi.object(op);
})
)
.description(
"Send operations to idchain to be applied to BrightID nodes' databases after consensus"
);

router
.put("/operations/:hash", handlers.operationsPut)
.pathParam(
"hash",
joi.string().required().description("sha256 hash of the operation message")
)
.body(schemas.schemas.operation)
.summary("Apply operation after consensus")
.description("Apply operation after consensus.")
.response(null);

module.context.use(function (req, res, next) {
try {
next();
} catch (e) {
if (e.cause && e.cause.isJoi) {
e.code = 400;
if (
req._raw.url.includes("operations") &&
e.cause.details &&
e.cause.details.length > 0
) {
let msg1 = "";
const msg2 = "invalid operation name";
e.cause.details.forEach((d) => {
if (!d.message.includes('"name" must be one of')) {
msg1 += `${d.message}, `;
}
});
e.message = msg1 || msg2;
}
}
console.group("Error returned");
console.log("url:", req._raw.requestType, req._raw.url);
console.log("error:", e);
console.log("body:", req.body);
console.groupEnd();
res.throw(e.code || 500, e);
}
});
Loading