// credit https://www.bostonglobe.com | |
function isIE10OrLater(user_agent) { | |
var ua = user_agent.toLowerCase(); | |
if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) { | |
return false; | |
} | |
var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua); | |
if (match && parseInt(match[1], 10) >= 10) { | |
return true; | |
} | |
// MS Edge Detection from this gist: https://gist.github.com/cou929/7973956 | |
var edge = /edge/.exec(ua); | |
if (edge && edge[0] == "edge") { | |
return true; | |
} | |
return false; | |
} | |
function detectPrivateMode(callback) { | |
var is_private; | |
if (window.webkitRequestFileSystem) { | |
window.webkitRequestFileSystem( | |
window.TEMPORARY, 1, | |
function() { | |
is_private = false; | |
}, | |
function(e) { | |
console.log(e); | |
is_private = true; | |
} | |
); | |
} else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) { | |
var db; | |
try { | |
db = window.indexedDB.open('test'); | |
} catch(e) { | |
is_private = true; | |
} | |
if (typeof is_private === 'undefined') { | |
retry( | |
function isDone() { | |
return db.readyState === 'done' ? true : false; | |
}, | |
function next(is_timeout) { | |
if (!is_timeout) { | |
is_private = db.result ? false : true; | |
} | |
} | |
); | |
} | |
} else if (isIE10OrLater(window.navigator.userAgent)) { | |
is_private = false; | |
try { | |
if (!window.indexedDB) { | |
is_private = true; | |
} | |
} catch (e) { | |
is_private = true; | |
} | |
} else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) { | |
// One-off check for weird sports 2.0 polyfill | |
// This also impacts iOS Firefox and Chrome (newer versions), apparently | |
// @see bglobe-js/containers/App.js:116 | |
if (window.safariIncognito) { | |
is_private = true; | |
} else { | |
try { | |
window.openDatabase(null, null, null, null); | |
} catch (e) { | |
is_private = true; | |
} | |
try { | |
window.localStorage.setItem('test', 1); | |
} catch(e) { | |
is_private = true; | |
} | |
} | |
if (typeof is_private === 'undefined') { | |
is_private = false; | |
window.localStorage.removeItem('test'); | |
} | |
} | |
retry( | |
function isDone() { | |
return typeof is_private !== 'undefined' ? true : false; | |
}, | |
function next(is_timeout) { | |
callback(is_private); | |
} | |
); | |
} |
// credit https://www.breakingviews.com/ | |
function incognitoBrowsers() { | |
return new Promise(function(resolve) { | |
var on = function() { | |
resolve(!0) | |
} | |
, off = function() { | |
resolve(!1) | |
}; | |
if (!window.webkitRequestFileSystem) { | |
if ('MozAppearance'in document.documentElement.style) { | |
var db = indexedDB.open('test'); | |
return db.onerror = on, | |
void (db.onsuccess = off) | |
} | |
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { | |
var isPrivate = !1; | |
try { | |
window.openDatabase(null, null, null, null) | |
} catch (_) { | |
isPrivate = !0 | |
} | |
isPrivate ? on() : off() | |
} | |
return off() | |
} | |
window.webkitRequestFileSystem(0, 0, off, on) | |
}) | |
} |
/* eslint-disable consistent-return */ | |
let on; | |
let off; | |
const isSafari = () => { | |
if (Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) { | |
return true; | |
} | |
if ( | |
// eslint-disable-next-line no-undef | |
(!window.safari || safari.pushNotification).toString() === '[object SafariRemoteNotification]' | |
) { | |
return true; | |
} | |
try { | |
return window.localStorage && /Safari/.test(window.navigator.userAgent); | |
} catch (e) { | |
return false; | |
} | |
}; | |
const isMozilla = () => 'MozAppearance' in document.documentElement.style; | |
const Webkit = () => { | |
if (window.webkitRequestFileSystem) { | |
window.webkitRequestFileSystem(window.TEMPORARY, 1, off, on); | |
return true; | |
} | |
}; | |
const Mozilla = () => { | |
if (isMozilla()) { | |
const db = indexedDB.open('test'); | |
db.onerror = on; | |
db.onsuccess = off; | |
return true; | |
} | |
}; | |
const Safari = () => { | |
if (isSafari()) { | |
// iOS 11 | |
// Origin: https://gist.github.com/cou929/7973956#gistcomment-2272103 | |
try { | |
window.openDatabase(null, null, null, null); | |
} catch (e) { | |
on(); | |
return true; | |
} | |
// Older Safari | |
try { | |
if (localStorage.length) off(); | |
else { | |
localStorage.x = 1; | |
localStorage.removeItem('x'); | |
off(); | |
} | |
} catch (e) { | |
// Original gist: https://gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1 | |
// Safari only enables cookie in private mode | |
// if cookie is disabled then all client side storage is disabled | |
// if all client side storage is disabled, then there is no point | |
// in using private mode | |
navigator.cookieEnabled ? on() : off(); // eslint-disable-line no-unused-expressions | |
} | |
return true; | |
} | |
}; | |
const IE10Edge = () => { | |
if (!window.indexedDB && (window.PointerEvent || window.MSPointerEvent)) { | |
on(); | |
return true; | |
} | |
}; | |
export const checkPrivate = (onCb, offCb) => { | |
on = onCb || (() => {}); | |
off = offCb || (() => {}); | |
Webkit() || Mozilla() || Safari() || IE10Edge() || off(); // eslint-disable-line no-unused-expressions | |
}; | |
export const checkPrivateWhitelist = (onCb, offCb) => { | |
const whitelistOn = onCb || (() => {}); | |
const whitelistOff = offCb || (() => {}); | |
const privateButAllowed = [ | |
'FBAV', | |
'FBAN', | |
'FBIOS', | |
'FBBV', | |
'FBDV', | |
'FBMD', | |
'FBSN', | |
'FBSV', | |
'FBSS', | |
'FBCR', | |
'FBID', | |
'FBLC', | |
'FBOP', | |
'Twitter for iPhone', | |
'TwitterAndroid', | |
'nytios', | |
'nytiphone', | |
'nytipad', | |
'nyt-android', | |
'AppleNews', | |
'Flipboard', | |
]; | |
const re = new RegExp(privateButAllowed.join('|'), 'i'); | |
if (re.test(navigator.userAgent)) { | |
whitelistOn(); | |
return true; | |
} | |
whitelistOff(); | |
return false; | |
}; |
function detectPrivateMode(cb) { | |
if( | |
navigator.userAgent.indexOf('WebKit') !== -1 | |
&& navigator.userAgent.indexOf('Mobile') !== -1 | |
){ | |
try { | |
window.openDatabase(null, null, null, null); | |
cb(false); | |
} catch (_) { | |
cb(true); | |
} | |
}else{ | |
var db, | |
on = cb.bind(null, true), | |
off = cb.bind(null, false) | |
function tryls() { | |
try { | |
localStorage.length ? off() : (localStorage.x = 1, localStorage.removeItem("x"), off()); | |
} catch (e) { | |
navigator.cookieEnabled ? on() : off(); | |
} | |
} | |
window.webkitRequestFileSystem ? webkitRequestFileSystem(0, 0, off, on) | |
: "MozAppearance" in document.documentElement.style ? (db = indexedDB.open("test"), db.onerror = on, db.onsuccess = off) | |
: /constructor/i.test(window.HTMLElement) || window.safari ? tryls() | |
: !window.indexedDB && (window.PointerEvent || window.MSPointerEvent) ? on() | |
: off() | |
} | |
} |
Thank you for publishing the great code.
I'm sorry if I become strange English for the following Japanese translation.
ttps: //output.jsbin.com/qanacid/1
I was open to test the judgment of the private mode, naturally it does not correspond to Chrome 76. This is because Google took measures.
iOS12 Private mode has been determined normally on iPhone Safari.
This mechanism is unknown,
bostonglobe.js
Line 68 of
if (window.safariIncognito) {
The part is likely to be a key, but no information is given.
Is it possible to determine iOS12 Safari with only simple Javascript?
This morning on the bostonglobe site, when I saw an article in Chrome (ver76) in private mode / guest mode, both received a private browser decision.
Normally, an account is created in the browser.
This is a perfect measure, but do you understand the structure?
I am very surprised that bostonglobe's countermeasures are too early.
Hi, since chrome 76 version this not work but i see that if you change, "window.TEMPORARY" to "window.PERSISTENT" in bostonglobe.js line 25 it's works.
Hi infoziko,
to detect browser I use that function:
function getBrowserInfo () { var ua = navigator.userAgent; var tem; var M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; if (/trident/i.test(M[1])) { tem = /\brv[ :]+(\d+)/g.exec(ua) || []; return { browser: 'IE', version: (tem[1] || '') } } if (M[1] === 'Chrome') { tem = ua.match(/\b(OPR|Edge)\/(\d+)/); if (tem != null) { return { browser: tem[1].replace('OPR', 'Opera'), version: (tem[2] || '') } } } M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'] if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]) return { browser: M[0], version: M[1] } }
Thank you for publishing the great code.
I'm sorry if I become strange English for the following Japanese translation.
ttps: //output.jsbin.com/qanacid/1
I was open to test the judgment of the private mode, naturally it does not correspond to Chrome 76. This is because Google took measures.
iOS12 Private mode has been determined normally on iPhone Safari.
This mechanism is unknown,
bostonglobe.js
Line 68 ofif (window.safariIncognito) {
The part is likely to be a key, but no information is given.
Is it possible to determine iOS12 Safari with only simple Javascript?
live version of boston globe code - https://output.jsbin.com/qanacid/1