Issues with identifying and encoding urls - javascript

I'm having issues with parsing/manipulating URI:
Problem Statement:
I want to encode f[users.comma] and return it.
[Case-1] I get an url from backend service, encode f[users.comma] and return it.
[Case-2] I get an url from backend service and f[users.comma] is already encoded. So don't double encode and return it.
Expected Output:
`/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22`
Code:
const encodedExample = `/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22` // the last param is encoded
const regularExample2 = `/demo/bigquery/order_items?fields=users.email&f[users.comma]="Abbeville, Georgia"` //
const specialEncode = (url) => {
for (let queryParam of urlObj) {
const [urlKey, urlValue] = queryParam
// Check to see if url contains f[users.comma]
if (urlKey.includes('f[')) {
urlObj.set(urlKey, encodeURI(urlValue))
}
}
return urlObj.toString() // doesn't seem to work
}
I feel like I am going offroad with my approach. I'd appreciate some help here.

Since the backend service returns an encoded or decode url
We can first decode the url from the backend service (this won't produce any exceptions if url is already encoded)
const encodedExample = `/demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%2C+Georgia%22` // the last param is encoded
const regularExample2 = `/demo/bigquery/order_items?fields=users.email&f[users.comma]="Abbeville, Georgia"`
const specialEncode = (url) => {
let decodedUrl = decodeURI(url);
let encodedUrl = encodeURI(decodedUrl);
// fix "f[users.comma]" because encodeURI will encode the [ and ] as well
encodedUrl = encodedUrl.replace("f%5Busers.comma%5D", "f[users.comma]")
console.log(encodedUrl);
return encodedUrl;
}
specialEncode(encodedExample); // logs and returns: /demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%252C+Georgia%22
specialEncode(regularExample2); // logs and returns: /demo/bigquery/order_items?fields=users.email&f[users.comma]=%22Abbeville%252C+Georgia%22
The code above works fine for both encoded and decoded urls

Related

How to get url parameters with same name from URL in js?

For example I have this url
https://www.test.com/test.html?categoryid=4&test1=12&test2=65&brand[0]=val1&brand[1]=val2&test3=15
Now how do I get value of brand[0]=val1&brand[1]=val2 but it can be any number of there in the url maybe brand[2],brand[3] etc... or none url can be without this parameter
I need to get if brand parameter is in url and if yes then I need to get all which are availabe in the url
Any help would be great!
So you don't really know if there would be parameters or not so that's why I can propose this solution right here it will parse all your parameters anyways and stack them in the config JSON in case there is no parameters config would be empty then on your DOMloaded event you can handle the cases as you want
const config = {};
const loadConfig = () => {
const urlQuery = new URLSearchParams(window.location.search);
urlQuery.forEach((e, k) => {
config[k] = e;
});
};
const onLoadEvent = () => {
console.log(config) // should contain all the query string params.
}

PublicKeyCredential not possible to serialize

I am implementing FIDO2(WebAuthn) in a Angular application.
I have gotten the PublicKeyCredentialCreationOptions object and seccessfullt register.
But after calling
let response = await navigator.credentials.create({'publicKey': myPublicKeyCredentialCreationOption })
I try to send the response to the server.. But this fails.
When I tried to look at the object in the browser using
console.log(JSON.stringify(response))
I get
{}
as output (?..) but when doing
console.log(response)
I get a object with values in the console...
How should the object get serialized to send to the server?
PublicKeyCredential objects contains ArrayBuffer objects that cannot be serialized as JSON. You could base64 encode these values in your Angular app and decode on the server to get the same byte array back. A helper library to do exactly that for WebAuthn exists: https://github.com/github/webauthn-json
Here's a very simple example for anyone who needs it:
function bufferToBase64url (buffer) {
// modified from https://github.com/github/webauthn-json/blob/main/src/webauthn-json/base64url.ts
const byteView = new Uint8Array(buffer);
let str = "";
for (const charCode of byteView) {
str += String.fromCharCode(charCode);
}
// Binary string to base64
const base64String = btoa(str);
// Base64 to base64url
// We assume that the base64url string is well-formed.
const base64urlString = base64String.replace(/\+/g, "-").replace(
/\//g,
"_",
).replace(/=/g, "");
return base64urlString;
}
...
create publicKeyCredentialCreationOptions
...
navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
}).then(credential => {
// credential created
// console.log(credential); <-- check what is output to see what you need to call bufferToBase64url(credential.<...>) on down below
// convert credential to json serializeable
const serializeable = {
authenticatorAttachment: credential.authenticatorAttachment,
id: credential.id,
rawId: bufferToBase64url(credential.rawId),
response: {
attestationObject: bufferToBase64url(credential.response.attestationObject),
clientDataJSON: bufferToBase64url(credential.response.clientDataJSON)
},
type: credential.type
};
const serialized = JSON.stringify(serializeable);
console.log(serialized);
}).catch(err => {
// an error occurred
console.error(err);
});

Generate JWT form header and payload

I'm Using node js to create a jwt in my backend server.
I'm using a library to sign/verify a JWT and it work fine. once one jwt.io i paste the token that i got when i sign in and i can see my data in the payload.
So the problem is that I'm trying to generate the signature from header and the payload that i got back in jwt.io
here is what i tryed to do but it did'nt work and i'm confuse a bit.
the algorith used to sign is the default one HS256.
const crypto = require("crypto");
// encode base64 the header
let jsonHeader = JSON.stringify({
alg: "HS256",
typ: "JWT",
});
let bs64header = Buffer.from(jsonHeader).toString("base64").split("=")[0];
console.log("bs64header :>>\n ", bs64header); //look the same as the token i got
// encode vase64 the payload
let jsonPayload = JSON.stringify({
id: "5eb20004ac94962628c68b91",
iat: 1589125343,
exp: 1589989343,
jti: "37743739b1476caa18ca899c7bc934e1aba63ba1",
});
let bs64payload = Buffer.from(jsonPayload).toString("base64").split("=")[0];
console.log("bs64Payload :>> \n", bs64payload); //look the same as the token i got
// TRY to generate the signature from the Base64Header and Base64Payload
// with the secret code that i used to sign the JWT
let secret = "0d528cb666023eee0d44e725fe9dfb751263d2f68f07998ae7388ff43b1b504f";
let signature = bs64header + "." + bs64payload;
let hashed = crypto
.createHash("sha256", secret)
.update(signature)
.digest("hex");
console.log("hashed :>> \n", hashed);
let bs64signature = Buffer.from(hashed).toString("base64").split("=")[0];
console.log("bs64signature>>", bs64signature); //This is where i got stuck.
// let jwt = bs64header + "." + bs64payload + "." + bs64signature;
// console.log("jwt>>", jwt);
I have modified your code a lot to make it less repetitive and easier to read. I am not entirely sure if this will work, so please comment if there are any errors.
I have tested it in runkit and have also checked what the output should be using jwt.io. The output appears to be the same, so I am pretty certain that this works.
Changes
Created a function to base64 encode objects and strings.
Created a function to make base64 strings use the URL safe character set.
Changed crypto.createHash() to crypto.createHmac(), so that a secret key can actually be used.
// base64 encode the data
function bs64encode(data) {
if (typeof data === "object") {
data = JSON.stringify(data);
}
return bs64escape(Buffer.from(data).toString("base64"));
}
// modify the base64 string to be URL safe
function bs64escape(string) {
return string.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
// base64 encode the header
let bs64header = bs64encode({
alg: "HS256",
typ: "JWT"
});
console.log("bs64header :>>\n ", bs64header);
// base64 encode the payload
let bs64payload = bs64encode({
id: "5eb20004ac94962628c68b91",
iat: 1589125343,
exp: 1589989343,
jti: "37743739b1476caa18ca899c7bc934e1aba63ba1"
});
console.log("bs64payload :>> \n", bs64payload);
// generate the signature from the header and payload
let secret = "0d528cb666023eee0d44e725fe9dfb751263d2f68f07998ae7388ff43b1b504f";
let signature = bs64header + "." + bs64payload;
let bs64signature = bs64escape(crypto
.createHmac("sha256", secret)
.update(signature)
.digest("base64"));
console.log("bs64signature>>", bs64signature);
let jwt = bs64header + "." + bs64payload + "." + bs64signature;
console.log("jwt>>", jwt);

NodeJS + ldapsj-client: problem saving thumbnailPhoto

Using the ldapsj-client module, I'm trying to save the thumbnailPhoto into a file
const auth = async () => {
const client = new LdapClient({ url: 'myaddomain' })
await client.bind('someemail#domain.com.br', 'passwaord')
const opts = {
filter: `(sAMAccountName=credential)`,
scope: "sub"
}
const s = await client.search(myBaseDN, opts)
console.log('thumbnailPhoto', s[0].thumbnailPhoto)
}
The console.log() outputs something like '����JFIF��C...'
I cannot figure out how to save this binary into a file. When I try several approaches, as explained here, does not work. It seems the data from AD is not in the same "format".
I tried to convert it into a Buffer and then, to base64
const buffer = Buffer.from(s[0].thumbnailPhoto, 'binary')
var src = "data:image/png;base64," + Buffer.from(s[0].thumbnailPhoto).toString('base64')
But the output is not a valid base64.

How to convert this signature method from crypto (node) to crypto-js (browser)?

I have a signature method that is meant to be used in Node.js but I'd like to implement it client-side with crypto-js. It should work in latest Chrome versions.
I have tried to follow some answers like this one: Decode a Base64 String using CryptoJS
But I either get errors such as "Error: Malformed UTF-8 data", or a different result than the expected hmacDigest.
I am not sure how I could find an alternative to the "binary" digest although I found this question:
How to get digest representation of CryptoJS.HmacSHA256 in JS
The method is supposed to answer the following:
"Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key"
This is the Nodejs version (with crypto):
const crypto = require('crypto')
function sign(path, params, secret) {
const message = querystring.stringify(params)
const secretBase64 = Buffer.from(secret, 'base64')
const hash = crypto.createHash('sha256')
const hmac = crypto.createHmac('sha512', secretBase64)
const hashDigest = hash.update(params.nonce + message).digest('binary')
const hmacDigest = hmac.update(path + hashDigest, 'binary').digest('base64')
return hmacDigest
}
note: querystring is just an helper module that can also run in browsers: https://nodejs.org/api/querystring.html
This is my attempt (wip) at implementing with crypto-js:
import cryptojs from 'crypto-js')
function sign (path, params, secret) {
const message = querystring.stringify(params)
const secretParsed = cryptojs.enc.Base64.parse(secret)
const secretDecoded = cryptojs.enc.Utf8.stringify(secretParsed) // -> this throws an error as "Error: Malformed UTF-8 data"
const hash = cryptojs.SHA256(params.nonce + message).toString(cryptojs.enc.hex)
const hmac = cryptojs.HmacSHA512(path + hash, secretDecoded).toString(cryptojs.enc.hex)
return hmac
}
Try this ! I think this is what you looking for !
const crypto = require("crypto")
const sign = (path, params, secret) => {
const message = querystring.stringify(params)
const secret = Buffer.from(secret, 'base64')
let sign = params.nonce + message
let hash = crypto.createHmac('sha256', secret)
.update(sign)
.digest("base64").toString()
let encoded = encodeURIComponent(hash)
return encoded
}

Categories

Resources