In our VueJS app I have a URL that is returned from an API that points to amer.example.com/put/stuff that I need to PUT some data.
Obviously when I do this PUT I get CORS errors. To remedy this I have a devServer proxy setup that says to reroute all /put/stuff to go through example.com like this:
devServer: {
port: 9034,
proxy: {
'/put/stuff': {
target: 'amer.example.com',
},
},
},
Voila, things start working again.
However, the URL that is returned from the API is dynamic and can be pointing to yet another region like EMEA, emea.example.com/put/stuff but everything else in the URL is the exact same.
How can I make the proxy dynamic so that it will go to amer.example.com, emea.example.com, or any other region based on the URL I get back from another API.
I have no control over the other API and how the URL that is returned is shaped.
The only way that I can think of to do this would be ugly, but it should work.
TLDR
Insert the region into the path of the URL you get back from the API, and then look for that path in the proxy. Finally use pathRewrite in your proxy to remove it from the URL.
Longer explanation
Create a new function in your methods that inserts the region into the URL path, like this:
methods: {
insertRegionIntoUrlPath(urlStr) {
const url = new URL(urlStr);
// Grab the region from the url, if it includes 'https://' then update the substring obviously).
const regionPath = `/${url.hostname.substring(0,4)}`;
// Set the path to now include the region in the beginning
url.pathname = `${regionPath}${url.pathname}`;
// Return the full URL that now contains the region: `https://amer.example.com/amer/put/stuff`
return url.href;
},
}
You would then use this function wherever that PUT is happening to add the region into the URL path.
I've made an assumptions that your region is always 4 characters long, if that could be different then just use some regex to pull the subdomain out.
Then in your proxy setup you can now target the specific region paths you want and remove the part of the path you added, like this:
module.exports = {
devServer: {
proxy: {
'/amer': {
target: 'https://amer.example.com',
pathRewrite: {'^/amer' : ''} // Removing `/amer` from the path
},
'/emea': {
target: 'https://emea.example.com/',
pathRewrite: {'^/emea' : ''} // Removing `/emea` from the path
}
}
}
};
So now what you have done is got a URL from the API, added the region into the path and made a PUT request and finally the proxy picks up these requests because they will match the region paths like /amer and then we simply have the proxy remove that part from the URL before the request is sent off.
Related
I'm setting up redirects for a client in Next.js. We have a configuration like so inside next.config.js:
{
source: '/page.aspx:urlstr*',
destination: 'https://someurl.com/page.aspx:urlstr*',
permanent: true,
},
The actual URLs hitting this will have a long URL string like so:
page.aspx?woXxJNrRIMKVC109awwTopP+k2NmkvXf+MzijTEc3zIZ3pf4n+Yknq
This is being URL encoded to be:
https://someurl.com/page.aspx?woXxJNrRIMKVC109awwTopP%20k2NmkvXf%20MzijTEc3zIZ3pf4n%20Yknq
The old server hosting these pages at the destination can't handle the URL encoded query string. Is there a way to force Next.js to not parse it?
So the solution was in fact to use the Next.js middleware feature:
https://nextjs.org/docs/advanced-features/middleware
It's a little buggy though. The docs say to add middleware.js to the same level as the pages directory, but you actually need to add _middleware.js inside the pages directory.
Also the matches feature does not seem to work for me at all, so here's my solution:
import { NextResponse } from 'next/server'
export function middleware(request) {
if (request.nextUrl.pathname.startsWith('/page.aspx')) {
let url = new URL(request.url);
return NextResponse.redirect(`https://someurl.com${url.pathname}${url.search}`)
}
}
I have a working Js plugin thats written in jQuery. For my plugin to work, I need to get the URL, but without the anchor tag that references an element by id. That is, only getting http://example.com/content/1/ instead of say http://example.com/content/1/#comments.
I am doing this with the following function :
var getProperURL = function() {
return window.location.protocol + '//' + window.location.hostname + window.location.pathname;
}
This works most of the time. However, I ran this on an angular project, and I only get the protocol and the hostname. How do I do this for AngularJs?
To retrieve only the path without the hash, you can use $location.path().
See the official documentation: location.path()
This method is getter / setter.
Return path of current url when called without any parameter.
Change path when called with parameter and return $location.
Note: Path should always begin with forward slash (/), this method will add the forward slash if it is missing.
Return full url representation with all segments encoded according to rules specified in RFC 3986.
Inject location and retrieve all datas you need. In the guide is plenty of examples:
// given url http://example.com/#/some/path?foo=bar&baz=xoxo
var path = $location.path();
// => "/some/path"
and in your website:
// given url http://example.com/content/1/#comments
var path = $location.path();
// => "/content/1"
I have a login page https://example.com/login#destination where destination is the target URL the user was trying to navigate to when they were required to log in.
(i.e. https://example.com/destination)
The JavaScript I was thinking about using was
function onSuccessfulLogin() {
location.replace(location.hash.substring(1) || 'default')
}
This would result in an XSS vulnerability, by an attacker providing the link
https://example.com/login#javascript:..
Also I need to prevent navigation to a lookalike site after login.
https://example.com/login#https://looks-like-example.com
or https://example.com/login#//looks-like-example.com
How can I adjust onSuccessfulLogin to ensure the URL provided in the hash # portion is a relative URL, and not starting with javascript:, https:, // or any other absolute navigation scheme?
One thought is to evaluate the URL, and see if location.origin remains unchanged before navigating. Can you suggest how to do this, or a better approach?
From OWASP recommendations on Preventing Unvalidated Redirects and Forwards:
It is recommended that any such destination input be mapped to a value, rather than the actual URL or portion of the URL, and that server side code translate this value to the target URL.
So a safe approach would be mapping some keys to actual URLs:
// https://example.com/login#destination
var keyToUrl = {
destination: 'https://example.com/destination',
defaults: 'https://example.com/default'
};
function onSuccessfulLogin() {
var hash = location.hash.substring(1);
var url = keyToUrl[hash] || keyToUrl.defaults;
location.replace(url);
}
You could also consider providing only path part of the URL and appending it with a hostname in the code:
// https://example.com/login#destination
function onSuccessfulLogin() {
var path = location.hash.substring(1);
var url = 'https://example.com/' + path;
location.replace(url);
}
I would stick to the mapping though.
That is a very good point about the XSS vulnerability.
I believe all protocols only use English alphabetic characters, so a regex like /^[a-z]+:/i would check for those. Alternately if we're feeling more inclusive, /^[^:\/?]+:/ allows anything but a / or ? followed by a :. Then we can combine that with /^\/\/ to test for a protocol-free URL, which gives us:
// Either
var rexIsProtocol = /(?:^[a-z]+:)|(?:^\/\/)/i;
// Or
var rexIsProtocol = /(?:^[^:\/?]+:)|(?:^\/\/)/i;
Then the test is like this:
var url = location.hash.substring(1).trim(); // trim to deal with whitespace
if (rexIsProtocol.test(url)) {
// It starts with a protocol
} else {
// It doesn't
}
That said, the only one I think you need to be particularly bothered by is the javascript: pseudo-protcol, so you might just test for that.
I'm doing an administrative function to work with CKEditor v4.x and need a file/folder view, upload and selection tool. For the time being I'm using CKFinder as I'd like to avoid writing a complete plugin by myself. However for the purpose I need to be able to switch baseDir and baseUrl dynamically.
I tried older code examples like
CKFinder.setupCKEditor(
editor,
{
basePath: '/ckfinder/',
baseUrl: 'http://www.example.com/mydirectory/',
baseDir: '/mydirectory/'
}
);
But this doesn't work. Apparently you need to set the paths by PHP (server side). As I'm having many CKEditor instances on one page, generated dynamically, and all should use different CKFinder paths it is a great deal of work if I need to change the path asynchronously through AJAX calls... I can of course see the security considerations by letting client side code control baseDir. For the record this application, and CKFinder, is only available after login by administrative people.
In our CMS area we use CKFinder.setupCKEditor() and I was unable to pass variables or flags to the config file correctly.
So I simply went to where the 'IsAuthorized' flag is set (that allows access to use CKFinder in their CheckAuthentication() function), and I set two more session variables: 'ckfinder_baseDir' and 'ckfinder_baseUrl'.
*Note that I have a Config class that checks the enviroment, hence Config::isDev(). You can check it any way that makes sense for you.
$_SESSION['IsAuthorized'] = 1;
$_SESSION['ckfinder_baseUrl'] = Config::isDev() ? 'http://devurl.com/' : 'http://produrl.com';
$_SESSION['ckfinder_baseUrl'] = Config::isDev() ? '/path/to/dev/uploads/' : 'path/to/prod/uploads';
Then I simply use these flags when in the CKFinder config.php file.
$baseUrl = $_SESSION['ckfinder_baseUrl'];
$baseDir = $_SESSION['ckfinder_baseDir'];
You can specify the parameter on the frontend side in the definition of the filebrowser button as following
{
type: 'button',
label:'Button for filebrowser',
filebrowser: {
action: 'Browse',
params: {
'id': '{someID}'
}
},
With help from the discussion Customize baseUrl and baseDir in CKFinder I got close to the answer with Travis comment.
There is a way to call different server side settings for each instance of CKFinder by just using a GET parameter in the path to CKFinder. I set the id of the filebrowserpath
filebrowserBrowseUrl: '/ckfinder/ckfinder.html?id=testdir'
And then in the config.php:
if ($_GET['id'] && $_GET['id'] == "testdir") {
$baseDir = $baseDir . 'testdir/';
$baseUrl = $baseUrl . 'testdir/';
}
This way each instance of CKeditor can use different basePath and baseUrl settings, and also other specific config.
in config.ascx in setConfig() method
string userName = string.Empty;
if (HttpContext.Current != null)
userName = HttpContext.Current.User.Identity.Name;
else
throw new Exception("User Name is not provided");
BaseUrl = "~/Uploads/Users/" + userName + "/";
I'm using TinyMCE for Editing my site content.
In Local I've different path for my base url and on development server its different and on production its different.
Is there any way to define the something like baseURL for my links and basePath for Images to be linked.
I want to define baseURL to all my links and basePath to my all the Images.
Right now I'm working on my local and I've created few pages. But when I've thought of dev and production It will be difficult to do the path changing task. Please desperately need some solution.
I think you will need to set these three options:
relative_urls : false,
remove_script_host : false,
document_base_url : "http://www.example.com/path1/"
According to the TinyMCE documentation, this will convert all relative urls to fully qualified URLs, based on the base you provide.
function myCustomURLConverter(url, node, on_save, name) {
// Do some custom URL conversion
if (name == "src")
{
url = window.location.origin +"/uploads/" + url
}
// Return new URL
return url;
}
I'm not sure I undestand the question, but wouldn't this provide what you're looking for?
var base = "http://"+window.location.host;
// base = "http://stackoverflow.com"
var img_base = base + "/img"
// img_base = "http://stackoverflow.com/img"