Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 97 additions & 28 deletions dist/hello.all.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/*! hellojs v1.20.0 - (c) 2012-2023 Andrew Dodson - MIT https://adodson.com/hello.js/LICENSE */
// ES5 Object.create
if (!Object.create) {

Expand Down Expand Up @@ -1453,32 +1452,109 @@ hello.utils.extend(hello.utils, {
var p;
var location = window.location;

// Is this an auth relay message which needs to call the proxy?
p = _this.param(location.search);
// Helper to robustly decode a state string that may be JSON, URL-encoded,
// HTML-entity encoded, or base64 encoded (provider specific quirks)
function decodeStateString(str) {
if (!str || typeof str !== 'string') {
return null;
}

// OAuth2 or OAuth1 server response?
if (p && p.state && (p.code || p.oauth_token)) {
function tryParse(jsonString) {
try { return JSON.parse(jsonString); } catch (e) { return null; }
}

try {
var state = JSON.parse(p.state);
function decodeURIComponentSafe(s) {
try { return decodeURIComponent(s); } catch (e) { return s; }
}

function unescapeSafe(s) {
try { return unescape(s); } catch (e) { return s; }
}

// Add this path as the redirect_uri
p.redirect_uri = state.redirect_uri || location.href.replace(/[\?\#].*$/, '');
function htmlEntityDecode(s) {
// Handle common encodings seen in wild redirects
return s
.replace(/"/g, '"')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/'/g, "'");
}

function atobSafe(s) {
try { return window.atob(s); } catch (e) { return null; }
}

// Redirect to the host
var path = _this.qs(state.oauth_proxy, p);
// Try raw JSON first
var obj = tryParse(str);
if (obj) { return obj; }

// Try URL-decoded once
var urlOnce = decodeURIComponentSafe(str);
obj = tryParse(urlOnce);
if (obj) { return obj; }

if (isValidUrl(path)) {
location.assign(path);
// Try unescape (covers some ISO-8859-1 escapes as seen with Amazon)
var unesc = unescapeSafe(str);
obj = tryParse(unesc);
if (obj) { return obj; }

// Try HTML-entity replacements
var html = htmlEntityDecode(str);
obj = tryParse(html);
if (obj) { return obj; }

// Try base64 (some providers require/return base64 state)
// Attempt straight, url-decoded, and HTML-entity cleaned variants
var candidates = [str, urlOnce, html];
for (var i = 0; i < candidates.length; i++) {
var c = candidates[i];
// Heuristic: base64 charset and padding
if (/^[A-Za-z0-9+/=_-]+$/.test(c)) {
// Replace URL-safe base64 chars if present
var normalized = c.replace(/-/g, '+').replace(/_/g, '/');
var padded = normalized + Array((4 - (normalized.length % 4)) % 4 + 1).join('=');
var b64 = atobSafe(padded);
if (b64) {
obj = tryParse(b64);
if (obj) { return obj; }
}
}
}

return;
// Last attempt: decodeURIComponent + unescape combo (legacy kludge)
var combo;
try { combo = decodeURIComponent(unescape(str)); } catch (e) { combo = null; }
if (combo) {
obj = tryParse(combo);
if (obj) { return obj; }
}
catch (e) {
console.error('Could not decode state parameter', e);

return null;
}

// Is this an auth relay message which needs to call the proxy?
p = _this.param(location.search);

// OAuth2 or OAuth1 server response?
if (p && p.state && (p.code || p.oauth_token)) {

var state = decodeStateString(p.state);
if (!state) {
console.error('Could not decode state parameter');
return;
}

// Add this path as the redirect_uri
p.redirect_uri = state.redirect_uri || location.href.replace(/[\?\#].*$/, '');

// Redirect to the host
var path = _this.qs(state.oauth_proxy, p);

if (isValidUrl(path)) {
location.assign(path);
}

return;
}

// Save session, from redirected authentication
Expand All @@ -1494,19 +1570,12 @@ hello.utils.extend(hello.utils, {

// Remove any addition information
// E.g. p.state = 'facebook.page';
try {
var a = JSON.parse(p.state);
_this.extend(p, a);
var parsedState = decodeStateString(p.state);
if (parsedState) {
_this.extend(p, parsedState);
}
catch (e) {
var stateDecoded = decodeURIComponent(p.state);
try {
var b = JSON.parse(stateDecoded);
_this.extend(p, b);
}
catch (e) {
console.error('Could not decode state parameter');
}
else {
console.error('Could not decode state parameter');
}

// Access_token?
Expand Down
3 changes: 1 addition & 2 deletions dist/hello.all.min.js

Large diffs are not rendered by default.

125 changes: 97 additions & 28 deletions dist/hello.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/*! hellojs v1.20.0 - (c) 2012-2023 Andrew Dodson - MIT https://adodson.com/hello.js/LICENSE */
// ES5 Object.create
if (!Object.create) {

Expand Down Expand Up @@ -1453,32 +1452,109 @@ hello.utils.extend(hello.utils, {
var p;
var location = window.location;

// Is this an auth relay message which needs to call the proxy?
p = _this.param(location.search);
// Helper to robustly decode a state string that may be JSON, URL-encoded,
// HTML-entity encoded, or base64 encoded (provider specific quirks)
function decodeStateString(str) {
if (!str || typeof str !== 'string') {
return null;
}

// OAuth2 or OAuth1 server response?
if (p && p.state && (p.code || p.oauth_token)) {
function tryParse(jsonString) {
try { return JSON.parse(jsonString); } catch (e) { return null; }
}

try {
var state = JSON.parse(p.state);
function decodeURIComponentSafe(s) {
try { return decodeURIComponent(s); } catch (e) { return s; }
}

function unescapeSafe(s) {
try { return unescape(s); } catch (e) { return s; }
}

// Add this path as the redirect_uri
p.redirect_uri = state.redirect_uri || location.href.replace(/[\?\#].*$/, '');
function htmlEntityDecode(s) {
// Handle common encodings seen in wild redirects
return s
.replace(/&#34;/g, '"')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/&apos;/g, "'");
}

function atobSafe(s) {
try { return window.atob(s); } catch (e) { return null; }
}

// Redirect to the host
var path = _this.qs(state.oauth_proxy, p);
// Try raw JSON first
var obj = tryParse(str);
if (obj) { return obj; }

// Try URL-decoded once
var urlOnce = decodeURIComponentSafe(str);
obj = tryParse(urlOnce);
if (obj) { return obj; }

if (isValidUrl(path)) {
location.assign(path);
// Try unescape (covers some ISO-8859-1 escapes as seen with Amazon)
var unesc = unescapeSafe(str);
obj = tryParse(unesc);
if (obj) { return obj; }

// Try HTML-entity replacements
var html = htmlEntityDecode(str);
obj = tryParse(html);
if (obj) { return obj; }

// Try base64 (some providers require/return base64 state)
// Attempt straight, url-decoded, and HTML-entity cleaned variants
var candidates = [str, urlOnce, html];
for (var i = 0; i < candidates.length; i++) {
var c = candidates[i];
// Heuristic: base64 charset and padding
if (/^[A-Za-z0-9+/=_-]+$/.test(c)) {
// Replace URL-safe base64 chars if present
var normalized = c.replace(/-/g, '+').replace(/_/g, '/');
var padded = normalized + Array((4 - (normalized.length % 4)) % 4 + 1).join('=');
var b64 = atobSafe(padded);
if (b64) {
obj = tryParse(b64);
if (obj) { return obj; }
}
}
}

return;
// Last attempt: decodeURIComponent + unescape combo (legacy kludge)
var combo;
try { combo = decodeURIComponent(unescape(str)); } catch (e) { combo = null; }
if (combo) {
obj = tryParse(combo);
if (obj) { return obj; }
}
catch (e) {
console.error('Could not decode state parameter', e);

return null;
}

// Is this an auth relay message which needs to call the proxy?
p = _this.param(location.search);

// OAuth2 or OAuth1 server response?
if (p && p.state && (p.code || p.oauth_token)) {

var state = decodeStateString(p.state);
if (!state) {
console.error('Could not decode state parameter');
return;
}

// Add this path as the redirect_uri
p.redirect_uri = state.redirect_uri || location.href.replace(/[\?\#].*$/, '');

// Redirect to the host
var path = _this.qs(state.oauth_proxy, p);

if (isValidUrl(path)) {
location.assign(path);
}

return;
}

// Save session, from redirected authentication
Expand All @@ -1494,19 +1570,12 @@ hello.utils.extend(hello.utils, {

// Remove any addition information
// E.g. p.state = 'facebook.page';
try {
var a = JSON.parse(p.state);
_this.extend(p, a);
var parsedState = decodeStateString(p.state);
if (parsedState) {
_this.extend(p, parsedState);
}
catch (e) {
var stateDecoded = decodeURIComponent(p.state);
try {
var b = JSON.parse(stateDecoded);
_this.extend(p, b);
}
catch (e) {
console.error('Could not decode state parameter');
}
else {
console.error('Could not decode state parameter');
}

// Access_token?
Expand Down
3 changes: 1 addition & 2 deletions dist/hello.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"url": "https://github.com/MrSwitch/hello.js/issues"
},
"scripts": {
"build": "bash ./build.sh",
"build": "node ./scripts/build.js",
"lint": "eslint ./",
"test": "npm run lint && npm run test:build && npm run test:headless",
"test:build": "npx rollup tests/specs/index.js --file tests/specs/bundle.js --format iife",
Expand Down
Loading