I am a new in Nodejs and libsodium.js. I have a task but I don't know how to solve it, and from where to start it. I'll appreciate if someone guides me. I have a class wallet inside it I need to generate public and private key then
class Wallet {
async create(): Promise<void> {
// must generate public / private key pair
// you can store files in the leveldb
}
async sign(content: string): Promise<string> {
// must return signature for the given content using previously generated public / private key pair
}
async verify(signature: string, content: string): Promise<boolean> {
// verifies if given signature was generated by previously generated public / private key pair
}
async encrypt(content: string): Promise<string> {
// must encrypt given string and return encrypted string (based on previously generated public / private key pair)
}
async decrypt(content): Promise<string> {
// must decrypt the given encrypted string and return original string (based on previously generated public / private key pair)
}
}
// usage
const wallet = new Wallet()
await wallet.create()
await wallet.sign("I am president") // must return signature
await wallet.verify(signature, "I am president") // must return true
await wallet.encrypt("I am president") // must return ecnrypted string
await wallet.decrypt(encrypted) // must return decrypted string
Related
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.
There is a Crypto class by custom made in nestjs.
import * as bcrypt from 'bcrypt';
export class Crypto {
constructor() {
}
public async hash(target: string, salt: number): Promise<string> {
return await bcrypt.hash(target, salt);
}
public async compareHash(
target: string,
hash: string,
): Promise<boolean> {
return await bcrypt.compare(target, hash);
}
}
And I made this instance in a service of nestjs as below.
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
const crypto = new Crypto();
const hashedPassword = await crypto.hash(createConfigDto.password, 10);
const newConfig = await new this.configModel({
...createConfigDto,
password: hashedPassword,
});
return newConfig.save();
}
public async read() {
const crypto = new Crypto();
const hashedPassword = await crypto.compare(createConfigDto.password, hash);
...
}
or I can do this crypto instance outside of create and read method to avoid duplicate call instance.
But my major question is about there is more efficient maintaining covention of nestjs for this case.
Could you give me some advice for me?
Thank you for reading my question.
To make your custom class Crypto a single instance and shared across the entire application, you should use #Injectable() decorator above your custom class
import * as bcrypt from 'bcrypt';
#Injectable()
export class Crypto {
constructor() {
}
public async hash(target: string, salt: number): Promise<string> {
return await bcrypt.hash(target, salt);
}
public async compareHash(
target: string,
hash: string,
): Promise<boolean> {
return await bcrypt.compare(target, hash);
}
}
After that, you should register your class (or service) in the module that contains this custom service:
#Module({
...
providers: [Crypto],
})
and finally, to use this service you can add to the constructor of your service
constructor(private crypto: Crypto) {}
....
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
const hashedPassword = await this.crypto.hash(createConfigDto.password, 10);
const newConfig = await new this.configModel({
...createConfigDto,
password: hashedPassword,
});
return newConfig.save();
}
public async read() {
const hashedPassword = await this.crypto.compare(createConfigDto.password, hash);
...
}
I recommend you to check this part of the official documentation providers
On the other hand, your custom service look that you may use it across the entire application, for that you can create a shared module and add all custom shared services on it, to understand more about that you can read this topic Shared Module
I am trying to pass my variable with generated password into my front-end side.
I think that my main problem is that I am generating password inside
route.post
this is my piece of fileUpload.route.ts
router.post('/upload-file', upload.array('file', 6), (req:any, res:any, next:any) => {
//...
genPass();
}
Inside genPass() is
let password = generator.generate({
length: 10,
numbers: true
});
I tried to do
module.exports = router, genPass;
and
router.get('/getpassword', fileController.fileGeneratedPassword);
Then inside my Controller
const password = require('../routes/fileUpload.route');
class FileController {
public async fileGeneratedPassword(req: Request, res: Response): Promise<void> {
console.log('pass: ' + JSON.stringify(password));
res.json(password);
}
}
But console.log is always empty.
How should I pass this variable?
I think that I must generate password inside router.post because when I upload in my frontend file then I want to generate password at the same time to "encrypt file".
I want to display generated password in my Angular frontend
module.exports returns a single value.
you can return an object if you like but I'd separate them into 2 files
generator
function genPass() {
return generator.generate({
length: 10,
numbers: true
});
}
module.exports = genPass
controller
const genPass = require('generator');
class FileController {
public async fileGeneratedPassword(req: Request, res: Response): Promise<void> {
const password = genPass()
console.log('pass: ' + JSON.stringify(password));
res.json(password);
}
}
Given a private key and a X.509 certificate (no RSA), I want to confirm that:
The private key is "valid".
It matches the certificate.
This validation would run in nodejs.
Example of valid private key (don't worry, testing purposes):
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSVkfyOqQ4E6No+v6
h/wotfYuGqiqierJ2YXx2v3rP1GhRANCAASMlEMAwv9jf8FAKDAxrnPGWVGBBzbD
wt3VQrrM5i/DOwCzF1XH7v6iYbvpYe9P0Qvf5ndqYYBklqLkXHAR37Vz
-----END PRIVATE KEY-----
Example of matching certificate:
-----BEGIN CERTIFICATE-----
MIICkDCCAjegAwIBAgIUCL+kBzVdqMGzurpuYwIxkuLbYrgwCgYIKoZIzj0EAwIw
czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT
E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkwMjA1MDgyMjAwWhcNMjAwMjA1MDgy
NzAwWjBDMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UECxMLZGVw
YXJ0bWVudDExDzANBgNVBAMTBm5hdGhhbjBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABIyUQwDC/2N/wUAoMDGuc8ZZUYEHNsPC3dVCuszmL8M7ALMXVcfu/qJhu+lh
70/RC9/md2phgGSWouRccBHftXOjgdgwgdUwDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
EwEB/wQCMAAwHQYDVR0OBBYEFJYSgUGno6j2eYUKjLs9BRzreUY1MCsGA1UdIwQk
MCKAIEI5qg3NdtruuLoM2nAYUdFFBNMarRst3dusalc2Xkl8MGkGCCoDBAUGBwgB
BF17ImF0dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMS5kZXBhcnRtZW50MSIs
ImhmLkVucm9sbG1lbnRJRCI6Im5hdGhhbiIsImhmLlR5cGUiOiJjbGllbnQifX0w
CgYIKoZIzj0EAwIDRwAwRAIgbYQ4UscWT5rgqLwrhcj8kRNN0kfA5n12Zpl1Fclw
+7QCIAlTx9oMsGBAeaNxJ3PV6mo9Zng5aMNnAmwW2PVcDlXt
-----END CERTIFICATE-----
You could attempt to create a secure context, using the built in node api. It will throw if the certificates don't match:
import tls from 'tls';
function testCertAndKeyMatch (cert, key) {
try {
tls.createSecureContext({ cert, key });
return true;
} catch (error) {
if (error.code === 'ERR_OSSL_X509_KEY_VALUES_MISMATCH') {
return false;
}
throw error;
}
}
You can use it like:
const cert = fs.readFileSync('./certs/cert.pem', 'utf8');
const key = fs.readFileSync('./certs/key.pem', 'utf8');
const isMatch = testCertAndKeyMatch(cert, key);
I have a javascript function that makes a post to a controller API. HereĀ“s the code:
exports.importList = function (req, res) {
res.setHeader('Content-Type', 'application/json');
var agencyId = req.user.agency_id;
var userId = req.user.id;
data = {
id_list: req.body.ids,
remoteHost:'127.0.0.1',
userId : userId,
agencyId:agencyId
};
call = '/ilist/importer/list/'; //Spring route
fetcher.post(call, 'post', data, function (err, result) {
console.log(data);
})
}
req.body.ids is an array of string values, so the data I want to send to my Controller has this structure:
{ id_list: [ '2147041', '2155271' ],
remoteHost: '127.0.0.1',
userId: 'user',
agencyId: 1 }
My controller method:
#RequestMapping(value="/list/", method = RequestMethod.POST, headers = "Accept=application/json")
public #ResponseBody RemaxResponse importPropertyList(#RequestBody ArrayList<String> data ) {
List<Long> ids = new ArrayList<>();
for (String id : data.id_list) {
ids.add(Long.valueOf(id));
}
response = ilistIImporterService.importPropertyList(ids);
return response;
}
I need to take in my Controller the array of strings and store it in an array of integer, and the other parameters store in integer variables.
Now, I'm getting that the data I send from javascript is sintactically incorrect. What's the proper way to do this?
If you want to send the whole object, I'd create a pojo and use that as #RequestBody like
public #ResponseBody RemaxResponse importPropertyList(#RequestBody RequestObject data ) {
Now spring can parse the whole data nicely to the given pojo, and you can simply use the getters to obtain the data you need.
A pojo could look like
public class RequestObject {
private List<Long> idList = null;
private String remoteHost;
private String userId;
private Integer agencyId;
public List<Long> getIdList() {
return idList;
}
public void setIdList(List<Long> idList) {
this.idList = idList;
}
public String getRemoteHost() {
return remoteHost;
}
public void setRemoteHost(String remoteHost) {
this.remoteHost = remoteHost;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getAgencyId() {
return agencyId;
}
public void setAgencyId(Integer agencyId) {
this.agencyId = agencyId;
}
}