我利用WhatsApp Flows API将流集成到我们的应用程序中。发布流时,我需要使用以下结构对其进行解密:
{
encrypted_flow_data: "<ENCRYPTED FLOW DATA>",
encrypted_aes_key: "<ENCRYPTED_AES_KEY>",
initial_vector: "<INITIAL VECTOR>"
}
字符串
参考此文档(https://developers. facebook.com/docs/whatsapp/flows/guides/implementingyourflowendpoint #nodejs-express-example)来解密密钥。
但是,我遇到了以下错误:
{
"code": "ERR_OSSL_RSA_OAEP_DECODING_ERROR",
"library": "rsa routines",
"reason": "oaep decoding error",
"message": "error:02000079:rsa routines::oaep decoding error",
"stack": "Error: error:02000079:rsa routines::oaep decoding error\n at Object.privateDecrypt (node:internal/crypto/cipher:79:12)\n at decryptRequest"
型
}
作为参考,这里是相关的代码片段:
const express = require("express");
const crypto = require("crypto");
const fs = require('fs');
const util = require('util');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);
require("dotenv").config();
const PORT = 3000;
const app = express();
app.use(express.json());
app.post("/data", async ({ body }, res) => {
const PRIVATE_KEY_PATH = 'path/to/your/private_key.pem';
const PRIVATE_KEY_PASSPHRASE = 'your_private_key_passphrase';
const PRIVATE_KEY = await readFile(PRIVATE_KEY_PATH, 'utf-8');
const { decryptedBody, aesKeyBuffer, initialVectorBuffer } = decryptRequest(
body,
PRIVATE_KEY,
PRIVATE_KEY_PASSPHRASE,
);
const { screen, data, version, action } = decryptedBody;
// Return the next screen & data to the client
const screenData = {
version,
screen: "SCREEN_NAME",
data: {
some_key: "some_value",
},
};
// Return the response as plaintext
res.send(encryptResponse(screenData, aesKeyBuffer, initialVectorBuffer));
});
const decryptRequest = async (body, privatePem, passphrase) => {
try {
const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body;
// Decrypt the AES key created by the client
const decryptedAesKey = crypto.privateDecrypt(
{
key: crypto.createPrivateKey(
{
key: privatePem,
passphrase: passphrase,
}
),
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256",
},
Buffer.from(encrypted_aes_key, "base64"),
);
// Decrypt the Flow data
const flowDataBuffer = Buffer.from(encrypted_flow_data, "base64");
const initialVectorBuffer = Buffer.from(initial_vector, "base64");
const TAG_LENGTH = 16;
const encrypted_flow_data_body = flowDataBuffer.subarray(0, -TAG_LENGTH);
const encrypted_flow_data_tag = flowDataBuffer.subarray(-TAG_LENGTH);
const decipher = crypto.createDecipheriv(
"aes-128-gcm",
decryptedAesKey,
initialVectorBuffer,
);
decipher.setAuthTag(encrypted_flow_data_tag);
const decryptedJSONString = Buffer.concat([
decipher.update(encrypted_flow_data_body),
decipher.final(),
]).toString("utf-8");
return {
decryptedBody: JSON.parse(decryptedJSONString),
aesKeyBuffer: decryptedAesKey,
initialVectorBuffer,
};
} catch (e) {
console.log('Error decoding:', e)
}
};
const encryptResponse = (
response,
aesKeyBuffer,
initialVectorBuffer,
) => {
// Flip the initialization vector
const flipped_iv = [];
for (const pair of initialVectorBuffer.entries()) {
flipped_iv.push(~pair[1]);
}
// Encrypt the response data
const cipher = crypto.createCipheriv(
"aes-128-gcm",
aesKeyBuffer,
Buffer.from(flipped_iv),
);
return Buffer.concat([
cipher.update(JSON.stringify(response), "utf-8"),
cipher.final(),
cipher.getAuthTag(),
]).toString("base64");
};
app.listen(PORT, () => {
console.log(`App is listening on port ${PORT}!`);
});
型
你能帮我解决这个问题吗?我很感激你的帮助。谢谢。
3条答案
按热度按时间u7up0aaq1#
如果您绝对确定您使用的私钥与Meta使用的公钥相对应,则继续使用方法1,否则首先执行方法2,如果错误仍然存在,则返回方法1。
方法一:
我也面临着同样的问题,现在虽然我不能具体解决这个错误,但我发现了一个来自Meta的小故障示例,这似乎对我有效(它不是抛出这个错误)。
访问故障项目(Meta版本)
我唯一要做改变是,当我把私钥放到环境变量中时,它抛出了错误,所以我把它放到了assets文件夹中,然后用fs来读取它作为参考,您可以访问我在Glitch上项目
访问故障项目(我的版本)
方法二:
1.更新服务器中的私钥。
1.使其工作的关键步骤:从WhatsApp客户端发出数据交换请求,并从您的webhook发送一个状态代码为421的错误,这将迫使WhatsApp客户端重新获取公钥。
字符串
1.要有耐心:通常,新生成的密钥对需要大约30分钟才能生效(从webhook回复状态代码421时算起)。
xlpyo6sf2#
我觉得解密代码没问题。问题可能出在私钥上。
1.你能验证私钥和公钥是否匹配吗?你可以记录私钥以确认它是正确的。
1.你能用公钥加密任何任意的有效载荷,并验证你能用当前的代码解密它吗?
mpbci0fu3#
我发现这取决于WELJ的版本。如果你使用的是版本100,那就不行了。但是使用版本200,反之亦然。但是现在,似乎版本100已经被弃用了。所以在你的WELJ文件中,放:
字符串
应该能用
还发现更新一个publicKey到Meta,我们需要等到他们的缓存生效。否则,所有的martedRequest都会用旧的publicKey加密。