I am using library to parse urls on my page:
import * as urlParse from 'url-parse';
const parseUrl = url => {
try {
return urlParse(url);
} catch (e) {
return null;
}
};
The issue is when the url 'www.stackoverflow.com' is passed to the function, parseUrl returns http:localhost\www.stackoverflow.com
should I use to obtain the value http://www.stackoverflow.com?
You don't really need any external lib for this:
const parser = document.createElement('a');
parser.href = '//www.stackoverflow.com';
console.log(`${parser.protocol}//${parser.hostname}`); // 'https://stackoverflow.com'
Related
I am trying to upgrade a working piece of code from Axios 0.27.2 to 1.0.0 and the way a URL with a query string is handled seems to break. That is, I get a 404 response and the actual URL used looks different than before in that the question mark is missing.
The URL looks like this: https://my.server.com/some/path?foo=bar&baz=abc
Previous axios used that. In the 1.0.0 version the actual URL sent, as reported in the error, is: https://my.server.com/some/pathfoo=bar&baz=abc
Similar questions all revolve around how to build a query string and the fact that axios accepts a params object for that. In my case, I am getting a URL from elsewhere that contains / may contain a query string already. How can I convince Axios to use this URL without changing it in some way?
axios.get('my-url', {
params: {
foo: "baz",
baz: "abc",
}
}).then(...)
Is need to specify if is CORS REQUEST (Set axios options, before request)
See https://github.com/axios/axios/issues/4999
This is a bug in Axios 1.0.0, fixed in 1.1.0
You can resolve this by building a function to split the received url into objects containing a base url and params before passing to axios.
function getUrlParams (url) {
const fullUrl = url;
const splitUrl = fullUrl.split("?");
const newUrl = splitUrl[0];
const paramsArray = splitUrl[1].split("&");
let paramsObj = {};
for(let i = 0; i < paramsArray.length; i++)
{
const arr = paramsArray[i].split("=");
const keyName = arr[0];
const value = arr[1];
paramsObj = {...paramsObj, [keyName]: value};
}
const data = {
base: newUrl,
params: paramsObj
}
return data;
}
const url = getUrlParams("https://my.server.com/some/path?foo=bar&baz=abc");
console.log(url)
Then for axios call you can do
axios.post(url.base, null, { params: url.params})
I have a html form and I want to create a json-file with data introduced in html fields.
Right now, it is visible in console json-text but it doesn't create a new json-file with this content. Also,I have an error, Uncaught ReferenceError: require is not defined.
// get the form element from dom
const formElement = document.querySelector('form#forms')
// convert the form to JSON
const getFormJSON = (form) => {
const data = new FormData(form);
return Array.from(data.keys()).reduce((result, key) => {
if (result[key]) {
result[key] = data.getAll(key)
return result
}
result[key] = data.get(key);
return result;
}, {});
};
// handle the form submission event, prevent default form behaviour, check validity, convert form to JSON
const handler = (event) => {
event.preventDefault();
const valid = formElement.reportValidity();
if (valid) {
const result = getFormJSON(formElement);
// handle one, multiple or no files uploaded
const images = [result.images].flat().filter((file) => !!file.name)
// handle one, multiple or no languages selected
const languages = [result.languages || []].flat();
// convert the checkbox to a boolean
const isHappyReader = !!(result.isHappyReader && result.isHappyReader === 'on')
// use spread function, but override the keys we've made changes to
const output = {
...result,
images,
languages,
isHappyReader
}
console.log(output)
}
}
formElement.addEventListener("submit", handler)
const fs = require('fs');
const dataNew = JSON.stringify(output);
fs.writeFile('output.json', dataNew, (err) => {
if (err) {
console.log("error")
throw err;
}
console.log("JSON data is saved.");
});
</script>
</body>
It seems you are on the frontend. You can't write files like this because of security. This would result in every website with some JavaScript being potentially able to write files to your system and you really don't want that.
Additionally fs is a Node API that is not available in the browser.
One option would be to download the JSON file from the frontend which you could do using the following code:
/**
* Download a JSON file.
* #param {sting} filename filename
* #param {any} obj any serializeable object
*/
function downloadJson(filename, obj) {
// serialize to JSON and pretty print with indent of 4
const text = JSON.stringify(obj, null, 4);
// create anchor tag
var element = document.createElement("a");
element.setAttribute(
"href",
"data:application/json;charset=utf-8," + encodeURIComponent(text)
);
element.setAttribute("download", filename);
// don't display the tag
element.style.display = "none";
// add tag to document
document.body.appendChild(element);
// click it: this starts the download
element.click();
// remove the tag again
document.body.removeChild(element);
}
window.addEventListener("DOMContentLoaded", (event) => {
// Start file download.
downloadJson("helloWorld.json", { hello: "World" });
});
If you add that to your page the save dialog will appear on a user's system. Here the one I am getting on Ubuntu:
And here the content of the downloaded file:
Please read this thread on the pros and cons of using an approach like this.
I'm trying to do this with just pure Javascript and the SDK. I am not using Node.js. I'm converting my application from v2 to v10 of the SDK azure-storage-js-v10
The azure-storage.blob.js bundled file is compatible with UMD
standard, if no module system is found, following global variable
will be exported: azblob
My code is here:
const serviceURL = new azblob.ServiceURL(`https://${account}.blob.core.windows.net${accountSas}`, pipeline);
const containerName = "container";
const containerURL = azblob.ContainerURL.fromServiceURL(serviceURL, containerName);
const blobURL = azblob.BlobURL.fromContainerURL(containerURL, blobName);
const downloadBlobResponse = await blobURL.download(azblob.Aborter.none, 0);
The downloadBlobResponse looks like this:
downloadBlobResponse
Using v10, how can I convert the downloadBlobResponse into a new blob so it can be used in the FileSaver saveAs() function?
In azure-storage-js-v2 this code worked on smaller files:
let readStream = blobService.createReadStream(containerName, blobName, (err, res) => {
if (error) {
// Handle read blob error
}
});
// Use event listener to receive data
readStream.on('data', data => {
// Uint8Array retrieved
// Convert the array back into a blob
var newBlob = new Blob([new Uint8Array(data)]);
// Saves file to the user's downloads directory
saveAs(newBlob, blobName); // FileSaver.js
});
I've tried everything to get v10 working, any help would be greatly appreciated.
Thanks,
You need to get the body by await blobBody.
downloadBlobResponse = await blobURL.download(azblob.Aborter.none, 0);
// data is a browser Blob type
const data = await downloadBlobResponse.blobBody;
Thanx Mike Coop and Xiaoning Liu!
I was busy making a Vuejs plugin to download blobs from a storage account. Thanx to you, I was able to make this work.
var FileSaver = require('file-saver');
const { BlobServiceClient } = require("#azure/storage-blob");
const downloadButton = document.getElementById("download-button");
const downloadFiles = async() => {
try {
if (fileList.selectedOptions.length > 0) {
reportStatus("Downloading files...");
for await (const option of fileList.selectedOptions) {
var blobName = option.text;
const account = '<account name>';
const sas = '<blob sas token>';
const containerName = '< container name>';
const blobServiceClient = new BlobServiceClient(`https://${account}.blob.core.windows.net${sas}`);
const containerClient = blobServiceClient.getContainerClient(containerName);
const blobClient = containerClient.getBlobClient(blobName);
const downloadBlockBlobResponse = await blobClient.download(blobName, 0, undefined);
const data = await downloadBlockBlobResponse.blobBody;
// Saves file to the user's downloads directory
FileSaver.saveAs(data, blobName); // FileSaver.js
}
reportStatus("Done.");
listFiles();
} else {
reportStatus("No files selected.");
}
} catch (error) {
reportStatus(error.message);
}
};
downloadButton.addEventListener("click", downloadFiles);
Thanks Xiaoning Liu!
I'm still learning about async javascript functions and promises. Guess I was just missing another "await". I saw that "downloadBlobResponse.blobBody" was a promise and also a blob type, but, I couldn't figure out why it wouldn't convert to a new blob. I kept getting the "Iterator getter is not callable" error.
Here's my final working solution:
// Create a BlobURL
const blobURL = azblob.BlobURL.fromContainerURL(containerURL, blobName);
// Download blob
downloadBlobResponse = await blobURL.download(azblob.Aborter.none, 0);
// In browsers, get downloaded data by accessing downloadBlockBlobResponse.blobBody
const data = await downloadBlobResponse.blobBody;
// Saves file to the user's downloads directory
saveAs(data, blobName); // FileSaver.js
I'm building a Facebook Page app in Classic ASP. I've been unable to match the signature that Facebook passes into the app as the first part of the POSTed signed_request.
Because there are few libraries for cryptography in VBScript, I'm using server side Javascript and the crypto-js library from https://code.google.com/archive/p/crypto-js/
I've tried to translate the PHP code example from Facebook's docs at https://developers.facebook.com/docs/games/gamesonfacebook/login#parsingsr into Javascript. I can generate an HMAC SHA256 hash of the signed_request payload but that doesn't match the signed_request signature.
I think the problem is that Facebook's signature is in a different format. It looks to be binary (~1抚Ö.....) while the HMAC SHA256 hash I'm generating is a hexadecimal string (7f7e8f5f.....). In Facebook's PHP example the hash_hmac function uses the raw binary parameter. So I think I need to either convert Facebook's signature to hexadecimal or my signature to binary in order to do an "apples-to-apples" comparison and get a match.
Here's my code:
/* Use the libraries from https://code.google.com/archive/p/crypto-js/
crypto-js/crypto-js.min.js
crypto-js/hmac-sha256.min.js
crypto-js/enc-base64.min.js
*/
var signedRequest = Request.queryString("signed_request")
var FB_APP_SECRET = "459f038.....";
var arSR = signedRequest.split(".");
var encodedSig = arSR[0];
var encodedPayload = arSR[1];
var payload = base64UrlDecode(encodedPayload);
var sig = base64UrlDecode(encodedSig);
var expectedSig;
expectedSig = CryptoJS.HmacSHA256(encodedPayload, FB_APP_SECRET); // Unaltered payload string; no match
expectedSig = CryptoJS.HmacSHA256(payload, FB_APP_SECRET); // base64-decoded payload string; no match
if (sig == expectedSig) {
Response.write(payload);
} else {
Response.write("Bad signature");
}
function base64UrlDecode(input) {
// Replace characters and convert from base64.
return Base64.decode(input.replace("-", "+").replace("_", "/"));
}
After looking into the crypto-js documentation about encoding I found the solution. The de-/encoding methods provided by crypto-js are listed under 'Encoders' at the bottom of https://code.google.com/archive/p/crypto-js/ (Thanks for the nudge, CBroe.)
The solution was to use .toString() on the signatures. It seems like crypto-js uses a word format that was preventing a comparison match. I did also switch to using the base64 decoding provided by crypto-js in order to stick with one library.
Here's my updated code:
/* Use the libraries from https://code.google.com/archive/p/crypto-js/
crypto-js/crypto-js.min.js
crypto-js/hmac-sha256.min.js
crypto-js/enc-base64.min.js
*/
var signedRequest = Request.queryString("signed_request")
var FB_APP_SECRET = "459f038.....";
var arSR = signedRequest.split(".");
var encodedSig = arSR[0];
var encodedPayload = arSR[1];
var payload = base64UrlDecode(encodedPayload);
var sig = base64UrlDecode(encodedSig);
var expectedSig = CryptoJS.HmacSHA256(encodedPayload, FB_APP_SECRET); /******** Correct payload */
if (sig.toString() != expectedSig.toString()) { /******* Use .toString() to convert to normal strings */
Response.write(payload);
} else {
Response.write("Bad signature");
}
function base64UrlDecode(input) {
return CryptoJS.enc.Base64.parse( /******** Decode */
input.replace("-", "+").replace("_", "/") // Replace characters
);
}
I recently implemented this for their required user data deletion webhook. No external dependencies needed anymore:
const crypto = require('crypto');
function parseSignedRequest(signedRequest, secret) {
const [signatureReceived, encodedPayload] = signedRequest.split('.', 2);
const payload = b64decode(encodedPayload)
const data = JSON.parse(payload);
const hmac = crypto.createHmac('sha256', secret).update(payload);
const expectedSignature = hmac.digest('base64');
if (signatureReceived === expectedSignature) {
return data;
} else {
throw new Error("Signature mismatch");
}
}
function b64decode(data) {
const buff = Buffer.from(data, 'base64');
return buff.toString('ascii');
}
It's a translation of their example PHP code. I also have a repo setup with tests.
I found this worked for me.
const crypto = require('crypto')
const _atob = (str) => Buffer.from(str, 'base64').toString('binary')
const parseSignedRequest = (signed_request, app_secret) => {
const [encoded_sig, payload] = signed_request.split('.')
const json = _atob(payload)
const data = JSON.parse(json)
if (!data.algorithm || data.algorithm.toUpperCase() !== 'HMAC-SHA256') {
return {error: true, type: 'Unknown algorithm. Expected HMAC-SHA256'}
}
// check sig
const expected_sig = crypto.createHmac('sha256', config.facebook.app_secret)
.update(payload).digest('base64')
.replace(/\+/g, '-').replace(/\//g, '_')
.replace(/=/g, '')
if (encoded_sig !== expected_sig) {
return ({error: true, type: 'invalid_signature'})
}
return {error: false, parsedRequest: data}
}
const {error, type, parsedRequest} = parseSignedRequest(signed_request)
How do I find the file extension of a URL using javascript?
example URL:
http://www.adobe.com/products/flashplayer/include/marquee/design.swf?width=792&height=294
I just want the 'swf' of the entire URL.
I need it to find the extension if the url was also in the following format
http://www.adobe.com/products/flashplayer/include/marquee/design.swf
Obviously this URL does not have the parameters behind it.
Anybody know?
Thanks in advance
function get_url_extension( url ) {
return url.split(/[#?]/)[0].split('.').pop().trim();
}
example:
get_url_extension('https://example.com/folder/file.jpg');
get_url_extension('https://example.com/fold.er/fil.e.jpg?param.eter#hash=12.345');
outputs ------> jpg
Something like this maybe?
var fileName = 'http://localhost/assets/images/main.jpg';
var extension = fileName.split('.').pop();
console.log(extension, extension === 'jpg');
The result you see in the console is.
jpg true
if for some reason you have a url like this something.jpg?name=blah or something.jpg#blah then you could do
extension = extension.split(/\#|\?/g)[0];
drop in
var fileExtension = function( url ) {
return url.split('.').pop().split(/\#|\?/)[0];
}
For the extension you could use this function:
function ext(url) {
// Remove everything to the last slash in URL
url = url.substr(1 + url.lastIndexOf("/"));
// Break URL at ? and take first part (file name, extension)
url = url.split('?')[0];
// Sometimes URL doesn't have ? but #, so we should aslo do the same for #
url = url.split('#')[0];
// Now we have only extension
return url;
}
Or shorter:
function ext(url) {
return (url = url.substr(1 + url.lastIndexOf("/")).split('?')[0]).split('#')[0].substr(url.lastIndexOf("."))
}
Examples:
ext("design.swf")
ext("/design.swf")
ext("http://www.adobe.com/products/flashplayer/include/marquee/design.swf")
ext("/marquee/design.swf?width=792&height=294")
ext("design.swf?f=aa.bb")
ext("../?design.swf?width=792&height=294&.XXX")
ext("http://www.example.com/some/page.html#fragment1")
ext("http://www.example.com/some/dynamic.php?foo=bar#fragment1")
Note:
File extension is provided with dot (.) at the beginning. So if result.charat(0) != "." there is no extension.
This is the answer:
var extension = path.match(/\.([^\./\?]+)($|\?)/)[1];
Take a look at regular expressions. Specifically, something like /([^.]+.[^?])\?/.
// Gets file extension from URL, or return false if there's no extension
function getExtension(url) {
// Extension starts after the first dot after the last slash
var extStart = url.indexOf('.',url.lastIndexOf('/')+1);
if (extStart==-1) return false;
var ext = url.substr(extStart+1),
// end of extension must be one of: end-of-string or question-mark or hash-mark
extEnd = ext.search(/$|[?#]/);
return ext.substring (0,extEnd);
}
url.split('?')[0].split('.').pop()
usually #hash is not part of the url but treated separately
This method works fine :
function getUrlExtension(url) {
try {
return url.match(/^https?:\/\/.*[\\\/][^\?#]*\.([a-zA-Z0-9]+)\??#?/)[1]
} catch (ignored) {
return false;
}
}
You can use the (relatively) new URL object to help you parse your url. The property pathname is especially useful because it returns the url path without the hostname and parameters.
let url = new URL('http://www.adobe.com/products/flashplayer/include/marquee/design.swf?width=792&height=294');
// the .pathname method returns the path
url.pathname; // returns "/products/flashplayer/include/marquee/design.swf"
// now get the file name
let filename = url.pathname.split('/').reverse()[0]
// returns "design.swf"
let ext = filename.split('.')[1];
// returns 'swf'
var doc = document.location.toString().substring(document.location.toString().lastIndexOf("/"))
alert(doc.substring(doc.lastIndexOf(".")))
const getUrlFileType = (url: string) => {
const u = new URL(url)
const ext = u.pathname.split(".").pop()
return ext === "/"
? undefined
: ext.toLowerCase()
}
function ext(url){
var ext = url.substr(url.lastIndexOf('/') + 1),
ext = ext.split('?')[0],
ext = ext.split('#')[0],
dot = ext.lastIndexOf('.');
return dot > -1 ? ext.substring(dot + 1) : '';
}
If you can use npm packages, File-type is another option.
They have browser support, so you can do this (taken from their docs):
const FileType = require('file-type/browser');
const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
(async () => {
const response = await fetch(url);
const fileType = await FileType.fromStream(response.body);
console.log(fileType);
//=> {ext: 'jpg', mime: 'image/jpeg'}
})();
It works for gifs too!
Actually, I like to imporve this answer, it means my answer will support # too:
const extExtractor = (url: string): string =>
url.split('?')[0].split('#')[0].split('.').pop() || '';
This function returns the file extension in any case.
If you wanna use this solution. these packages are using latest import/export method.
in case you wanna use const/require bcz your project is using commonJS you should downgrade to older version.
i used
"got": "11.8.5","file-type": "16.5.4",
const FileType = require('file-type');
const got = require('got');
const url ='https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
(async () => {
const stream = got.stream(url);
console.log(await FileType.fromStream(stream));
})();
var fileExtension = function( url ) {
var length=url.split(?,1);
return length
}
document.write("the url is :"+length);