Skip to content
Snippets Groups Projects
Commit ca77a784 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

order gets signed after purchase

parent 74e9963c
No related branches found
No related tags found
No related merge requests found
const config = require("config");
const { pki, random } = require("node-forge");
const crypto = require("crypto");
const BlindSignature = require("blind-signatures");
var BigInteger = require("jsbn").BigInteger;
const NodeRSA = require("node-rsa");
class Crypto {
#dayjs;
......@@ -17,24 +20,21 @@ class Crypto {
}
private_key_get_current() {
let seed_date = this.#dayjs().format(this.#dayjs_format);
let seed_date = this.#dayjs();
return this.#private_key_get(seed_date);
}
private_key_get_last() {
let seed_date = this.#dayjs()
.subtract(1, "month")
.format(this.#dayjs_format);
let seed_date = this.#dayjs().subtract(1, "month");
return this.#private_key_get(seed_date);
}
async #private_key_get(seed_date) {
let private_key = {};
let cache_key = "private_keys" + seed_date;
let cache_key = "private_key_" + seed_date.format(this.#dayjs_format);
// Check if the private key already exists in cache
let cached_key = await this.#redis.get(cache_key);
let private_key = new NodeRSA();
if (cached_key === null) {
let seed = config.get("crypto.private_key.seed") + seed_date;
......@@ -43,31 +43,45 @@ class Crypto {
prng_instance.seedFileSync = () => seed;
let keypair = pki.rsa.generateKeyPair({
bits: 4096,
bits: config.get("crypto.private_key.bit_length"),
prng: prng_instance,
workers: -1,
});
let private_key_pem = pki
.privateKeyToPem(keypair.privateKey)
.trim()
.replace(/\r\n/g, "\n");
private_key = {
n: keypair.privateKey.n.toString(),
e: keypair.privateKey.e.toString(),
d: keypair.privateKey.d.toString(),
p: keypair.privateKey.p.toString(),
q: keypair.privateKey.q.toString(),
dmp1: keypair.privateKey.dP.toString(),
dmq1: keypair.privateKey.dQ.toString(),
coeff: keypair.privateKey.qInv.toString(),
};
private_key = private_key.importKey(
Buffer.from(private_key_pem, "utf8"),
"private"
);
// Store the key in cache
await this.#redis.set(cache_key, JSON.stringify(private_key));
await this.#redis.set(cache_key, private_key.exportKey("pkcs8"));
} else {
private_key = JSON.parse(await this.#redis.get(cache_key));
let private_key_data = await this.#redis.get(cache_key);
private_key = private_key.importKey(private_key_data, "pkcs8");
}
return private_key;
}
async sign(encrypted_sales_receipts, order_date) {
let private_key = await this.#private_key_get(order_date);
console.log(private_key);
let signed_encrypted_sales_receipts = [];
for (let i = 0; i < encrypted_sales_receipts.length; i++) {
signed_encrypted_sales_receipts.push(
BlindSignature.sign({
blinded: new BigInteger(encrypted_sales_receipts[i]),
key: private_key,
}).toString()
);
}
return signed_encrypted_sales_receipts;
}
/**
* Creates an hmac hash for purchase data so we can check it later
*/
......@@ -84,8 +98,8 @@ class Crypto {
amount: parseInt(amount),
unit_size: parseInt(unit_size),
price_per_unit: parseFloat(price_per_unit),
public_key_n: public_key_n,
public_key_e: public_key_e,
public_key_n: new String(public_key_n),
public_key_e: new String(public_key_e),
});
let forge = require("node-forge");
let hmac = forge.hmac.create();
......@@ -111,8 +125,8 @@ class Crypto {
amount: parseInt(amount),
unit_size: parseInt(unit_size),
price_per_unit: parseFloat(price_per_unit),
public_key_n: public_key_n,
public_key_e: public_key_e,
public_key_n: new String(public_key_n),
public_key_e: new String(public_key_e),
});
let forge = require("node-forge");
let hmac = forge.hmac.create();
......
const config = require("config");
const Crypto = require("./Crypto");
const dayjs = require("dayjs");
class Order {
......@@ -34,12 +35,14 @@ class Order {
#unit_size;
#price_per_unit;
#encrypted_sales_receipts;
#signatures;
#payment_completed;
#payment_method_link; // Stores a link to an entry of the payment methods payment i.e. PayPal order id
/**
* Data populated by context
*/
#order_date;
#create_mode;
#redis_client;
......@@ -48,14 +51,23 @@ class Order {
amount,
unit_size,
price_per_unit,
encrypted_sales_receipts
encrypted_sales_receipts,
signatures
) {
this.#order_id = parseInt(order_id);
this.#order_id = new String(order_id);
this.#order_date = dayjs.unix(this.#order_id.substr(0, 10));
this.#amount = parseInt(amount);
this.#unit_size = parseInt(unit_size);
this.#price_per_unit = parseFloat(price_per_unit);
this.#encrypted_sales_receipts = encrypted_sales_receipts;
if (signatures) {
this.#signatures = signatures;
} else {
this.#signatures = [];
}
this.#payment_completed = false;
this.#create_mode = true;
......@@ -81,6 +93,10 @@ class Order {
return this.#payment_method_link;
}
getSignatures() {
return this.#signatures;
}
isPaymentComplete() {
return this.#payment_completed;
}
......@@ -89,6 +105,16 @@ class Order {
this.#payment_method_link = payment_method_link;
}
async signOrder() {
let mgcrypto = new Crypto();
let signed_encrypted_sales_receipts = mgcrypto.sign(
this.#encrypted_sales_receipts,
this.#order_date
);
this.#signatures = await signed_encrypted_sales_receipts;
}
static async LOAD_ORDER_FROM_ID(order_id) {
return new Promise((resolve, reject) => {
let Redis = require("ioredis");
......@@ -106,7 +132,8 @@ class Order {
order_data.amount,
order_data.unit_size,
order_data.price_per_unit,
order_data.encrypted_sales_receipts
JSON.parse(order_data.encrypted_sales_receipts),
JSON.parse(order_data.signatures)
);
if (order_data.payment_method_link) {
loaded_order.setPaymentMethodLink(
......@@ -140,7 +167,10 @@ class Order {
amount: this.#amount,
unit_size: this.#unit_size,
price_per_unit: this.#price_per_unit,
encrypted_sales_receipts: this.#encrypted_sales_receipts,
encrypted_sales_receipts: JSON.stringify(
this.#encrypted_sales_receipts
),
signatures: JSON.stringify(this.#signatures),
payment_completed: this.#payment_completed,
payment_method_link: JSON.stringify(this.#payment_method_link),
})
......
......@@ -70,7 +70,7 @@ function execute_payment_paypal(encrypted_sales_receipts) {
.then((orderData) => {
let paymentEvent = new CustomEvent("payment-complete", {
detail: {
orderData,
signatures: orderData.signatures,
},
bubbles: true,
cancelable: true,
......
......@@ -35,8 +35,8 @@ router.get(
let crypto = new Crypto();
let private_key = await crypto.private_key_get_current();
params.crypto = {
N: private_key.n,
E: private_key.e,
N: private_key.keyPair.n,
E: private_key.keyPair.e,
};
// Generate hmac hash of the payment data so we are able to verify them when the client submits them again
......@@ -87,6 +87,7 @@ router.use(
req.body.public_key_e
)
) {
console.log("Invalid integrity");
return Promise.reject("Integrity is not matching");
}
return true;
......
......@@ -18,6 +18,7 @@ router.post("/", async (req, res, next) => {
req.body.price_per_unit,
req.body.encrypted_sales_receipts
);
order
.save()
.then(() => {
......@@ -38,10 +39,30 @@ router.post("/", async (req, res, next) => {
// capture payment & store order information or fullfill order
router.post("/capture", async (req, res) => {
Order.LOAD_ORDER_FROM_ID(req.body.order_id).then((loaded_order) => {
let paypal_order_id = loaded_order.getPaymentMethodLink().id;
capturePayment(paypal_order_id).then((captureData) =>
res.json(captureData)
);
loaded_order
.signOrder()
.then(() => {
let paypal_order_id = loaded_order.getPaymentMethodLink().id;
capturePayment(paypal_order_id)
.then((captureData) => {
loaded_order
.save()
.then(() => {
captureData.signatures = loaded_order.getSignatures();
res.json(captureData);
})
.catch((error) => {
res.status(400).json({ errors: [{ msg: error }] });
});
})
.catch((error) => {
res.status(400).json({ errors: [{ msg: error }] });
});
})
.catch((error) => {
res.status(400).json({ errors: [{ msg: error }] });
});
//res.json(captureData);
// TODO: store payment information such as the transaction ID
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment