const {readCredential, writeCredential, deleteCredential} = require('./utils/cred')
const jose = require('node-jose');
const fetch = require('node-fetch'); // use version 2 when working with commonJS modules
const xsenv = require("@sap/xsenv");
xsenv.loadEnv();
const binding = xsenv.getServices({ credstore: { tag: 'credstore' } }).credstore;
function checkStatus(response) {
if (!response.ok) console.log(`Please verify that you CredStore binding info is up to date
Unexpected status code: ${response.status}`);
return response;
}
async function decryptPayload(privateKey, payload) {
const key = await jose.JWK.asKey(`-----BEGIN PRIVATE KEY-----${privateKey}-----END PRIVATE KEY-----`,
"pem",
{ alg: "RSA-OAEP-256", enc: "A256GCM" }
);
const decrypt = await jose.JWE.createDecrypt(key).decrypt(payload);
const result = decrypt.plaintext.toString();
return result;
}
async function encryptPayload(publicKey, payload) {
const key = await jose.JWK.asKey(`-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----`,
"pem",
{ alg: "RSA-OAEP-256" }
);
const options = {
contentAlg: "A256GCM",
compact: true,
fields: { "iat": Math.round(new Date().getTime() / 1000) }
};
return jose.JWE.createEncrypt(options, key).update(Buffer.from(payload, "utf8")).final();
}
function headers(binding, namespace, init) {
const headers = new fetch.Headers(init);
headers.set("Authorization", `Basic ${Buffer.from(`${binding.username}:${binding.password}`).toString("base64")}`);
headers.set("sapcp-credstore-namespace", namespace);
return headers;
}
async function fetchAndDecrypt(privateKey, url, method, headers, body) {
return fetch(url, { method, headers, body })
.then((resFetch)=>{
const resCheckStatus = checkStatus(resFetch)
return(resCheckStatus)})
.then((response) => {
const resText = response.text()
return resText
})
.then(payload => decryptPayload(privateKey, payload))
.then((resObj)=>{
return(JSON.parse(resObj))})
.catch(e=>{
`opps 😞 we have an issue: ${JSON.stringify(e)}`
});
}
async function readCredential(namespace, type, name) {
const headersToSend = headers(binding, namespace)
const resData = await fetchAndDecrypt(
binding.encryption.client_private_key,
`${binding.url}/${type}?name=${encodeURIComponent(name)}`,
"get",
headersToSend
);
return(resData)
}
async function writeCredential( namespace, type, credential) {
const headersToSend = headers(binding, namespace, { "Content-Type": "application/jose" })
const bodyToSend = await encryptPayload(binding.encryption.server_public_key, JSON.stringify(credential))
const resData = await fetchAndDecrypt(
binding.encryption.client_private_key,
`${binding.url}/${type}`,
"post",
headersToSend,
bodyToSend
);
return(resData)
}
async function deleteCredential(namespace, type, name) {
await fetch(
`${binding.url}/${type}?name=${encodeURIComponent(name)}`,
{
method: "delete",
headers: headers(binding, namespace)
}
).then(checkStatus);
}
module.exports = {readCredential, writeCredential, deleteCredential}
app.get('/testCredStore',async(req,res)=>{
const {readCredential, writeCredential, deleteCredential} = require('./utils/cred')
const testItem = {
name: "password1",
value: "myVerySecretMessage",
username: "user1",
metadata: "if you see this text, the cred store is working :)"
};
const writeRes = await writeCredential("test-ns", "password", testItem)
const readRes = await readCredential("test-ns", "password", "password1")
testItem.value="secret2"
await writeCredential("test-ns", "password", testItem)
const readAfterUpdate = await readCredential("test-ns", "password", "password1")
await deleteCredential("test-ns", "password", "password1")
res.json({writeRes, readRes, readAfterUpdate})
})
// http://localhost:4004/testCredStore
{
"writeRes": {
"id": "95dd3b54-0e3f-40e5-8a9f-517a01df5dd1",
"name": "password1",
"modifiedAt": "2022-06-27T12:38:08.540Z",
"metadata": "if you see this text, the cred store is working :)",
"status": "enabled",
"username": "user1",
"type": "password"
},
"readRes": {
"id": "95dd3b54-0e3f-40e5-8a9f-517a01df5dd1",
"name": "password1",
"modifiedAt": "2022-06-27T12:38:08.540Z",
"metadata": "if you see this text, the cred store is working :)",
"value": "myVerySecretMessage",
"status": "enabled",
"username": "user1",
"type": "password"
},
"readAfterUpdate": {
"id": "19e64f55-a6b6-48dc-bd36-db638ef610cd",
"name": "password1",
"modifiedAt": "2022-06-27T12:38:09.688Z",
"metadata": "if you see this text, the cred store is working :)",
"value": "secret2",
"status": "enabled",
"username": "user1",
"type": "password"
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
13 | |
10 | |
10 | |
7 | |
7 | |
6 | |
5 | |
5 | |
5 | |
4 |