JavaScript Handling Promise Response and Saving the response to MYSQL (PHP) - javascript

So I have this pre-built Javascript from Vendor which only returns Promise (https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt). Now that I managed to get the response into Console.log. I wish to save this Response to mysql using PHP.
My function looks like below which basically takes rawdata and using public Key via windows crypto and generates a Encryption sent to the vendor for verification:
function encryptfunction(dataPB, pKey, cb) {
var crypto = window.crypto || window.msCrypto;
if(crypto.subtle)
{
// fetch the part of the PEM string between header and footer
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
const pemContents = pKey.substring(pemHeader.length, pKey.length - pemFooter.length);
// base64 decode the string to get the binary data
const binaryDerString = window.atob(pemContents);
// convert from a binary string to an ArrayBuffer
const binaryDer = str2ab(binaryDerString);
crypto.subtle.importKey(
"spki",
binaryDer,
{
name: "RSA-OAEP",
hash: {
name: "SHA-512"
}
},
false, ["encrypt"]).then(
key => {
crypto.subtle.encrypt("RSA-OAEP", dataPB, pinBlock).then(
result => cb(btoa(ab2str(result))),
reason => console.log('encrypt failed', reason)
);
},
reason => console.log('import failed', reason));
}
else
{
alert("Cryptography API not Supported");
}
}
and my HTML
<textarea id="output" rows="20" cols="80"></textarea>';
so when I call my Function:
encryptfunction(pbdata, pKey,r => document.getElementById("output").value = r);
The reponse is shows in the ID (Textarea) properly, but I m having difficulty in storing this value to mysql using PHP due to two reasons.
The value "Response" is a promise which can not be accessed outside the function
The PHP page which runs these code is called into the application via CURL. (which means i just need to return or echo the RESPONSE.
Any tips or suggestion would be highly appreciated.

Related

How do I send a YAML file as a base64 encoded string?

I am trying to send a yaml file as a base64 string so that this code works:
const response = await octokit.request('GET /repos/{owner}/{repo}/git/blobs/{file_sha}', {
owner: 'DevEx',
repo: 'hpdev-content',
file_sha: fileSha,
headers: {
authorization: `Bearer ${githubConfig?.token}`,
},
});
const decoded = Buffer.from(response.data.content, 'base64').toString('utf8');
In the above code response.data.content should have the data.
I have this route:
router.get('/repos/:owner/:repo/git/blobs/:file_sha', (req, res) => {
// TODO: do we need to do anything with the path params?
// eslint-disable-next-line #typescript-eslint/no-unused-vars
const { owner, repo, file_sha } = req.params;
const contents = writeUsersReport();
const encoded = Buffer.from(contents, 'binary').toString('base64');
res.send(encoded);
});
The code is working fine except that the client code expects the base64 string in a property called content in the following code:
const decoded = Buffer.from(response.data.content, 'base64').toString('utf8');
But the string is in response.data.
How can I set the content property instead?
How about sending a json response containing an object with a content property from your server side instead of the encoded string directly?
// ...
const encoded = Buffer.from(contents, 'binary').toString('base64');
res.json({content:encoded});

Error when trying to display an image saved in a computer file

I am developing an application which allows me to bring some files saved from another server for that I have a code made in Asp.net which I consume with Javascript to bring the image, but when I get the image to show it, the following generates me error, Not allowed to load local resource: file: /// C: /Users/usuario/Desktop/imagenes/prfil/descarga.png, but when I copy the same link in the browser if it brings me the image:
This is my code .net:
public IHttpActionResult Get(string nombreArchivo)
{
string directorio = "C:\Users\usuario\Desktop\imagenes\"
string ruta = directorio + nombreArchivo;
if (File.Exists(ruta))
{
var result = new
{
imagen = ruta.Replace('\\', '/')
}
return Ok(result);
}
else
{
var result = new
{
imagen = "No existe la imagen"
}
return Ok(result);
}
}
And this my code JavaScript:
const file = async () => {
const res = await fetch(`http://localhost:64108/api/Archivos/?nombreArchivo=perfil/descarga.png`);
const datos = await res.json();
foto.style.backgroundImage = `url('${datos.imagen}')`;
};
Browsers use the local file:// protocol to load local files, which is only allowed for local calls. Same thing with HTTP protocol; it won't work to use this protocol followed by the full path of a local file. Yet, you have at least two options here. You either provide a public folder within your application's root directory, where you can access the file using a relative URI, which is the safer way of doing it.
Another possible approach is to return a file instead of a path. For this one, you may do something like this:
Javascript
let url = "http://localhost:64108/api/Archivos/?nombreArchivo=perfil/descarga.png";
let init = {
method: 'GET',
headers: {
'Accept': 'image/png'
}
};
fetch(url, init)
.then(function (res) {
// ...
})
.catch(function (err) {
// ...
});
C#
public IHttpActionResult Get(string nombreArchivo)
{
string directorio = "C:\\Users\\usuario\\Desktop\\imagenes\\";
string ruta = directorio + nombreArchivo;
if (System.IO.File.Exists(ruta))
return File(path, Request.Headers["Accept"]); // We've already set this to "image/png" in the javascript part
else return BadRequest("No existe la imagen");
}

Read CSV over SSH and convert to JSON

This is a duplicate of this question here
Here is the code I'm trying to work with:
let Client = require('ssh2-sftp-client');
let sftp = new Client();
var csv = require("csvtojson");
sftp.connect({
host: 'HOST',
port: 'PORT',
username: 'USERNAME',
password: 'PASSWORD'
}).then(() => {
return sftp.get('/home/user/etc/testfile.csv');
}).then((data) => {
csv()
.fromString(data.toString()) // changed this from .fromStream(data)
.subscribe(function(jsonObj) { //single json object will be emitted for each csv line
// parse each json asynchronously
return new Promise(function(resolve, reject) {
resolve()
console.log(jsonObj);
})
})
}).catch((err) => {
console.log(err, 'catch error');
});
I can read back the CSV data, and can see it going into JSON format on console.log(jsonObj) but the data is unreadable, all '\x00o\x00n\x00'' ..
I'm not sure what to do in the line:
// parse each json asynchronously
Could anyone help to figure out how to parse the CSV/JSON after it comes back from the buffer?
The null bytes \x00 are pointing towards an encoding/decoding issue. The CSV file might be encoded using UTF-16, but Buffer.toString() by default decodes the data using UTF-8. You can change that to data.toString('utf16le') (or data.toString('ucs2')) to force using the correct encoding.

Encryption/decryption functions working differently within Outlook add-in versus unit tests

I am working on an Outlook add-in that S/MIME encrypts/decrypts an email that you are currently composing. I have two functions shown at the end that perform S/MIME encryption/decryption respectively utilizing PKI.js. When running unit tests testing their functionality/correctness, they both work just fine, however when calling the very same functions from within an Outlook add-in (called when buttons are pressed) using the same certificate/key as the unit tests, I encounter the following error when attempting to decrypt some previously encrypted text:
Error: Decryption failed
at RsaOaepProvider.onDecrypt (webcrypto.es.js:1136)
at RsaOaepProvider.decrypt (webcrypto-core.es.js:173)
at SubtleCrypto.decrypt (webcrypto-core.es.js:826)
at CryptoEngine.decrypt (CryptoEngine.js:809)
at SubKeyTransRecipientInfo (EnvelopedData.js:1454)
The following is a unit test that passes just fine (Jest framework configured to run as though it were running in a browser):
const plaintext = "This is some plaintext.";
test("encrypt and decrypt some plaintext", async () => {
const encryptedText = await smimeEncrypt(plaintext, cert);
const decryptedText = await smimeDecrypt(encryptedText, key, cert);
expect(decryptedText).toBe(plaintext);
});
Versus the code called (that errors) whenever a button is pressed within the Outlook add-in:
let encryptedText = await smimeEncrypt(emailBody, cert);
await smimeDecrypt(encryptedText, key, cert).then((decryptedText) => {
console.log(decryptedText);
}).catch((err) => {
// Problem decrypting
console.error("Couldn't decrypt email. (Not an S/MIME message?)", err);
return;
});
I've verified that the emailBody being passed into smimeEncrypt() within the Outlook add-in is the actual email body string that it should be and not blank or anything else. Again, the exact same certificate and key are used for the unit tests that are used within the Outlook add-in itself, so an invalid cert/key pair should not be the issue.
emailFunctions.ts
import { Crypto } from "#peculiar/webcrypto";
import * as asn1js from "asn1js";
import { Convert } from "pvtsutils";
import * as pkijs from "pkijs";
import MimeNode from "emailjs-mime-builder";
import smimeParse from "emailjs-mime-parser";
// Set crypto engine
const crypto = new Crypto();
const engineName = "#peculiar/webcrypto";
pkijs.setEngine(
engineName,
crypto,
new pkijs.CryptoEngine({ name: engineName, crypto: crypto, subtle: crypto.subtle })
);
async function smimeEncrypt(
text: string,
certificatePem: string,
oaepHashAlgo: string = "SHA-256",
encryptionAlgo: string = "AES-CBC",
length: Number = 128
): Promise<string> {
// Decode input certificate
const asn1 = asn1js.fromBER(PemConverter.decode(certificatePem)[0]);
const certSimpl = new pkijs.Certificate({ schema: asn1.result });
const cmsEnveloped = new pkijs.EnvelopedData();
cmsEnveloped.addRecipientByCertificate(certSimpl, { oaepHashAlgorithm: oaepHashAlgo });
await cmsEnveloped.encrypt({ name: encryptionAlgo, length: length }, Convert.FromUtf8String(text));
const cmsContentSimpl = new pkijs.ContentInfo();
cmsContentSimpl.contentType = "1.2.840.113549.1.7.3";
cmsContentSimpl.content = cmsEnveloped.toSchema();
const schema = cmsContentSimpl.toSchema();
const ber = schema.toBER(false);
// Insert enveloped data into new Mime message
const mimeBuilder = new MimeNode("application/pkcs7-mime; name=smime.p7m; smime-type=enveloped-data; charset=binary")
.setHeader("content-description", "Enveloped Data")
.setHeader("content-disposition", "attachment; filename=smime.p7m")
.setHeader("content-transfer-encoding", "base64")
.setContent(new Uint8Array(ber));
mimeBuilder.setHeader("from", "sender#example.com");
mimeBuilder.setHeader("to", "recipient#example.com");
mimeBuilder.setHeader("subject", "Example S/MIME encrypted message");
return mimeBuilder.build();
}
async function smimeDecrypt(text: string, privateKeyPem: string, certificatePem: string): Promise<string> {
// Decode input certificate
let asn1 = asn1js.fromBER(PemConverter.decode(certificatePem)[0]);
const certSimpl = new pkijs.Certificate({ schema: asn1.result });
// Decode input private key
const privateKeyBuffer = PemConverter.decode(privateKeyPem)[0];
// Parse S/MIME message to get CMS enveloped content
try {
const parser = smimeParse(text);
// Make all CMS data
asn1 = asn1js.fromBER(parser.content.buffer);
if (asn1.offset === -1) {
alert('Unable to parse your data. Please check you have "Content-Type: charset=binary" in your S/MIME message');
return;
}
const cmsContentSimpl = new pkijs.ContentInfo({ schema: asn1.result });
const cmsEnvelopedSimpl = new pkijs.EnvelopedData({ schema: cmsContentSimpl.content });
const message = await cmsEnvelopedSimpl.decrypt(0, {
recipientCertificate: certSimpl,
recipientPrivateKey: privateKeyBuffer,
});
return Convert.ToUtf8String(message);
} catch (err) {
// Not an S/MIME message
throw err;
}
}
The full project repo can be found at https://github.com/gmu-msl/pkijs_outlook_addin_example, with some additional details and directions on how to install and test the behavior locally. Any insight as to what is causing this discrepancy and/or how to fix it would be greatly appreciated.

Passing a js var into a solidity function

Wrote a function in solidity which is like this,
function AddData(uint _index, string _projectName, string _devAddress, string _developer) public {
Datas[_index] = Data(_index, 0, _projectName, _devAddress, _developer);
}
Note that this is just a fragment of the whole solidity code. In js, i'm trying to pass variables into the functions but doesnt seem to be working. I assume it's the js variables unable to pass into solidity string variables.
counterDB.AddData(id_db, projectName, devAddress, developer, function (err, result) {
if (err) {
console.log('Error: ' + err);
}
else {
console.log(result);
}
});
The variables passed in are data i pulled out from the database to pass into the smart contract. I checked every data has been pulled in properly but i cant pass the data into the function. Am i missing a function to convert the var into string?
Are you using web3 v1.0 ? Have you tried to pass the function like this:
var yourContract = new web3.eth.Contract(ABI, contractAddress);
const contractFunction = yourContract.methods.AddData(id_db, projectName, devAddress, developer);
const functionBytes = contractFunction.encodeABI();
const rawTx = {
gasLimit: web3.utils.toHex(200000),
to: contractAddress,
from: addressFrom,
data: functionBytes
};
web3.eth.accounts.signTransaction(rawTx, privateKey)
.then(RLPencodedTx => {
web3.eth.sendSignedTransaction(RLPencodedTx['rawTransaction'])
.on('error', error => { callback(null, error) })
.on('receipt', receipt => { callback(receipt) });
})
Keep in mind, that you have to decrypt the private key if you are using the json export of it:
var path = process.cwd();
const exportedAccountString = fs.readFileSync(path + '/your_key_file.json').toString();
const decrypted = web3.eth.accounts.decrypt(exportedAccountString, 'YourPasswordHere...');
const privateKey = decrypted.privateKey;

Categories