4 Commits

Author SHA1 Message Date
cgalo5758 b53803f36d 0.2.0 2026-06-22 18:14:46 -05:00
cgalo5758 0e1b0b4771 Support ESM providers (.default unwrap); target wiki-security-social 2026-06-22 18:14:32 -05:00
cgalo5758 0d80674a0d Stop tracking generated client/ assets (already gitignored) 2026-06-22 17:17:16 -05:00
Robert Best 68e76c14c6 bump passportjs version again 2026-05-19 00:52:17 -04:00
8 changed files with 144 additions and 1373 deletions
-1021
View File
File diff suppressed because it is too large Load Diff
-10
View File
@@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<script>
function doPost(msg, origin) {
window.parent.postMessage(msg, origin);
}
</script>
</html>
-13
View File
@@ -1,13 +0,0 @@
#security #show-security-dialog, #logout, #claim{
color: gold;
}
#security #addAltAuth, #claim {
color: floralwhite;
}
.notOwner {
transform: rotate(20deg);
}
-301
View File
@@ -1,301 +0,0 @@
var WinChan = (function() {
var RELAY_FRAME_NAME = "__winchan_relay_frame";
var CLOSE_CMD = "die";
// a portable addListener implementation
function addListener(w, event, cb) {
if(w.attachEvent) w.attachEvent('on' + event, cb);
else if (w.addEventListener) w.addEventListener(event, cb, false);
}
// a portable removeListener implementation
function removeListener(w, event, cb) {
if(w.detachEvent) w.detachEvent('on' + event, cb);
else if (w.removeEventListener) w.removeEventListener(event, cb, false);
}
// checking for IE8 or above
function isInternetExplorer() {
var rv = -1; // Return value assumes failure.
var ua = navigator.userAgent;
if (navigator.appName === 'Microsoft Internet Explorer') {
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null)
rv = parseFloat(RegExp.$1);
}
// IE > 11
else if (ua.indexOf("Trident") > -1) {
var re = new RegExp("rv:([0-9]{2,2}[\.0-9]{0,})");
if (re.exec(ua) !== null) {
rv = parseFloat(RegExp.$1);
}
}
return rv >= 8;
}
// checking Mobile Firefox (Fennec)
function isFennec() {
try {
// We must check for both XUL and Java versions of Fennec. Both have
// distinct UA strings.
var userAgent = navigator.userAgent;
return (userAgent.indexOf('Fennec/') != -1) || // XUL
(userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1); // Java
} catch(e) {}
return false;
}
// feature checking to see if this platform is supported at all
function isSupported() {
return (window.JSON && window.JSON.stringify &&
window.JSON.parse && window.postMessage);
}
// given a URL, extract the origin. Taken from: https://github.com/firebase/firebase-simple-login/blob/d2cb95b9f812d8488bdbfba51c3a7c153ba1a074/js/src/simple-login/transports/WinChan.js#L25-L30
function extractOrigin(url) {
if (!/^https?:\/\//.test(url)) url = window.location.href;
var m = /^(https?:\/\/[\-_a-zA-Z\.0-9:]+)/.exec(url);
if (m) return m[1];
return url;
}
// find the relay iframe in the opener
function findRelay() {
var loc = window.location;
var frames = window.opener.frames;
for (var i = frames.length - 1; i >= 0; i--) {
try {
if (frames[i].location.protocol === window.location.protocol &&
frames[i].location.host === window.location.host &&
frames[i].name === RELAY_FRAME_NAME)
{
return frames[i];
}
} catch(e) { }
}
return;
}
var isIE = isInternetExplorer();
if (isSupported()) {
/* General flow:
* 0. user clicks
* (IE SPECIFIC) 1. caller adds relay iframe (served from trusted domain) to DOM
* 2. caller opens window (with content from trusted domain)
* 3. window on opening adds a listener to 'message'
* (IE SPECIFIC) 4. window on opening finds iframe
* 5. window checks if iframe is "loaded" - has a 'doPost' function yet
* (IE SPECIFIC5) 5a. if iframe.doPost exists, window uses it to send ready event to caller
* (IE SPECIFIC5) 5b. if iframe.doPost doesn't exist, window waits for frame ready
* (IE SPECIFIC5) 5bi. once ready, window calls iframe.doPost to send ready event
* 6. caller upon reciept of 'ready', sends args
*/
return {
open: function(opts, cb) {
if (!cb) throw "missing required callback argument";
// test required options
var err;
if (!opts.url) err = "missing required 'url' parameter";
if (!opts.relay_url) err = "missing required 'relay_url' parameter";
if (err) setTimeout(function() { cb(err); }, 0);
// supply default options
if (!opts.window_name) opts.window_name = null;
if (!opts.window_features || isFennec()) opts.window_features = undefined;
// opts.params may be undefined
var iframe;
// sanity check, are url and relay_url the same origin?
var origin = extractOrigin(opts.url);
if (origin !== extractOrigin(opts.relay_url)) {
return setTimeout(function() {
cb('invalid arguments: origin of url and relay_url must match');
}, 0);
}
var messageTarget;
if (isIE) {
// first we need to add a "relay" iframe to the document that's served
// from the target domain. We can postmessage into a iframe, but not a
// window
iframe = document.createElement("iframe");
// iframe.setAttribute('name', framename);
iframe.setAttribute('src', opts.relay_url);
iframe.style.display = "none";
iframe.setAttribute('name', RELAY_FRAME_NAME);
document.body.appendChild(iframe);
messageTarget = iframe.contentWindow;
}
var w = opts.popup || window.open(opts.url, opts.window_name, opts.window_features);
if (opts.popup) {
w.location.href = opts.url;
}
if (!messageTarget) messageTarget = w;
// lets listen in case the window blows up before telling us
var closeInterval = setInterval(function() {
if (w && w.closed) {
cleanup();
if (cb) {
cb('User closed the popup window');
cb = null;
}
}
}, 500);
var req = JSON.stringify({a: 'request', d: opts.params});
// cleanup on unload
function cleanup() {
if (iframe) document.body.removeChild(iframe);
iframe = undefined;
if (closeInterval) closeInterval = clearInterval(closeInterval);
removeListener(window, 'message', onMessage);
removeListener(window, 'unload', cleanup);
if (w) {
try {
w.close();
} catch (securityViolation) {
// This happens in Opera 12 sometimes
// see https://github.com/mozilla/browserid/issues/1844
messageTarget.postMessage(CLOSE_CMD, origin);
}
}
w = messageTarget = undefined;
}
addListener(window, 'unload', cleanup);
function onMessage(e) {
if (e.origin !== origin) { return; }
try {
var d = JSON.parse(e.data);
if (d.a === 'ready') messageTarget.postMessage(req, origin);
else if (d.a === 'error') {
cleanup();
if (cb) {
cb(d.d);
cb = null;
}
} else if (d.a === 'response') {
cleanup();
if (cb) {
cb(null, d.d);
cb = null;
}
}
} catch(err) { }
}
addListener(window, 'message', onMessage);
return {
close: cleanup,
focus: function() {
if (w) {
try {
w.focus();
} catch (e) {
// IE7 blows up here, do nothing
}
}
}
};
},
onOpen: function(cb) {
var o = "*";
var msgTarget = isIE ? findRelay() : window.opener;
if (!msgTarget) throw "can't find relay frame";
function doPost(msg) {
msg = JSON.stringify(msg);
if (isIE) msgTarget.doPost(msg, o);
else msgTarget.postMessage(msg, o);
}
function onMessage(e) {
// only one message gets through, but let's make sure it's actually
// the message we're looking for (other code may be using
// postmessage) - we do this by ensuring the payload can
// be parsed, and it's got an 'a' (action) value of 'request'.
var d;
try {
d = JSON.parse(e.data);
} catch(err) { }
if (!d || d.a !== 'request') return;
removeListener(window, 'message', onMessage);
o = e.origin;
if (cb) {
// this setTimeout is critically important for IE8 -
// in ie8 sometimes addListener for 'message' can synchronously
// cause your callback to be invoked. awesome.
setTimeout(function() {
cb(o, d.d, function(r) {
cb = undefined;
doPost({a: 'response', d: r});
});
}, 0);
}
}
function onDie(e) {
if (e.data === CLOSE_CMD) {
try { window.close(); } catch (o_O) {}
}
}
addListener(isIE ? msgTarget : window, 'message', onMessage);
addListener(isIE ? msgTarget : window, 'message', onDie);
// we cannot post to our parent that we're ready before the iframe
// is loaded. (IE specific possible failure)
try {
doPost({a: "ready"});
} catch(e) {
// this code should never be exectued outside IE
addListener(msgTarget, 'load', function(e) {
doPost({a: "ready"});
});
}
// if window is unloaded and the client hasn't called cb, it's an error
var onUnload = function() {
try {
// IE8 doesn't like this...
removeListener(isIE ? msgTarget : window, 'message', onDie);
} catch (ohWell) { }
if (cb) doPost({ a: 'error', d: 'client closed window' });
cb = undefined;
// explicitly close the window, in case the client is trying to reload or nav
try { window.close(); } catch (e) { }
};
addListener(window, 'unload', onUnload);
return {
detach: function() {
removeListener(window, 'unload', onUnload);
}
};
}
};
} else {
return {
open: function(url, winopts, arg, cb) {
setTimeout(function() { cb("unsupported browser"); }, 0);
},
onOpen: function(cb) {
setTimeout(function() { cb("unsupported browser"); }, 0);
}
};
}
})();
if (typeof module !== 'undefined' && module.exports) {
module.exports = WinChan;
}
+5 -2
View File
@@ -5,7 +5,7 @@
* while maintaining compatibility with the existing security interface.
*/
// Register CoffeeScript to allow requiring .coffee files. Needed for wiki-security-passportjs
// Register CoffeeScript to allow requiring .coffee files. Needed for CoffeeScript-based providers (e.g. wiki-security-friends)
require('coffeescript/register');
const _ = require('lodash');
@@ -42,7 +42,10 @@ module.exports = (log, loga, argv) => {
if (typeof authProvider === 'function') {
baseHandler = authProvider(log, loga, argv);
} else {
const AuthProvider = require(authProvider);
const mod = require(authProvider);
// ESM providers (e.g. wiki-security-social) expose the factory as `.default`;
// CommonJS providers (friends, passportjs) return the factory directly.
const AuthProvider = typeof mod === 'function' ? mod : mod.default;
baseHandler = AuthProvider(log, loga, argv);
}
} catch (error) {
+129 -18
View File
@@ -1,12 +1,12 @@
{
"name": "wiki-security-composable",
"version": "0.1.2",
"version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wiki-security-composable",
"version": "0.1.2",
"version": "0.2.0",
"license": "MIT",
"dependencies": {
"coffeescript": "^1.12.7",
@@ -18,7 +18,7 @@
},
"peerDependencies": {
"wiki-security-friends": "*",
"wiki-security-passportjs": "^0.13.0"
"wiki-security-passportjs": "^0.14.0"
}
},
"node_modules/@isaacs/cliui": {
@@ -61,9 +61,9 @@
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.9.9",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.9.tgz",
"integrity": "sha512-qycIHAucxy/LXAYIjmLmtQ8q9GPnMbnjG1KXhWm9o5sCr6pOYDATkMPiTNa6/v8eELyqOQ2FsEqeoFYmgv/gJg==",
"version": "0.9.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
"integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==",
"license": "MIT",
"peer": true,
"engines": {
@@ -90,9 +90,9 @@
}
},
"node_modules/brace-expansion": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@@ -128,6 +128,39 @@
"node": ">= 8"
}
},
"node_modules/express-handlebars": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-9.0.1.tgz",
"integrity": "sha512-zkU1G3SHfOXFMVlfZuYruOw5U2oaz+GsDEmnVfE4n5Gx0l+4si61lmFzjsHvu2OTmcabafBETAWg+HmAjLpAMA==",
"license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"glob": "^13.0.6",
"graceful-fs": "^4.2.11",
"handlebars": "^4.7.9"
},
"engines": {
"node": ">=22.22.2"
}
},
"node_modules/express-handlebars/node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"license": "BlueOak-1.0.0",
"peer": true,
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -168,6 +201,35 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC",
"peer": true
},
"node_modules/handlebars": {
"version": "4.7.9",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"minimist": "^1.2.5",
"neo-async": "^2.6.2",
"source-map": "^0.6.1",
"wordwrap": "^1.0.0"
},
"bin": {
"handlebars": "bin/handlebars"
},
"engines": {
"node": ">=0.4.7"
},
"optionalDependencies": {
"uglify-js": "^3.1.4"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -206,9 +268,9 @@
"license": "MIT"
},
"node_modules/lru-cache": {
"version": "11.2.7",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz",
"integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==",
"version": "11.4.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz",
"integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==",
"license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
@@ -229,6 +291,16 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@@ -238,6 +310,13 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"license": "MIT",
"peer": true
},
"node_modules/oauth": {
"version": "0.9.15",
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
@@ -417,6 +496,30 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/uglify-js": {
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
"license": "BSD-2-Clause",
"optional": true,
"peer": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/uid2": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz",
@@ -450,9 +553,9 @@
}
},
"node_modules/wiki-security-friends": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/wiki-security-friends/-/wiki-security-friends-0.3.0.tgz",
"integrity": "sha512-OM0/QeL9Zmm16sovrMsHjMP5j/AgwlAb1/9z5kX++WzsnTagac3Duj+dTzSh/cYid2Yt4gZpKWVJYhg32MBrPg==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/wiki-security-friends/-/wiki-security-friends-0.3.1.tgz",
"integrity": "sha512-J5wlqDrNBLp6dpnWt5VSZX+ZvjzvmDSzrXjF3XtzQkCeeE8rBtApqDoY2Asjl+5jM0aCffDMch4B8o5d4uWr8g==",
"license": "MIT",
"peer": true,
"dependencies": {
@@ -478,14 +581,15 @@
}
},
"node_modules/wiki-security-passportjs": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/wiki-security-passportjs/-/wiki-security-passportjs-0.13.0.tgz",
"integrity": "sha512-JYhF+58xd/w9fd8GaZVvRMytgSeytbEiezZ7roSbwpfmQcG0sRH4mKJ+OzhbO5lfoR8/PzQzqyFOveHVFwFN4g==",
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/wiki-security-passportjs/-/wiki-security-passportjs-0.14.0.tgz",
"integrity": "sha512-fgpl9+MrVoB5MmNLx0yaNMi4IUW5LY1D+eoM6D9ogs3ImdrO9yG2XsQoEuEHbWJekmYqp0aR0cxjNKvf+arl9A==",
"license": "MIT",
"peer": true,
"dependencies": {
"@passport-js/passport-twitter": "^1.0.8",
"coffeescript": "^2.4.1",
"express-handlebars": "^9.0.1",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.19",
"passport": "^0.3.2",
@@ -507,6 +611,13 @@
"engines": {
"node": ">=6"
}
},
"node_modules/wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
"license": "MIT",
"peer": true
}
}
}
+10 -2
View File
@@ -1,6 +1,6 @@
{
"name": "wiki-security-composable",
"version": "0.1.2",
"version": "0.2.0",
"description": "Composable security plugin foundation for Federated Wiki",
"main": "index.js",
"keywords": [
@@ -30,7 +30,15 @@
},
"peerDependencies": {
"wiki-security-friends": "*",
"wiki-security-passportjs": "^0.13.0"
"wiki-security-social": "^0.1.0-rc.5"
},
"peerDependenciesMeta": {
"wiki-security-friends": {
"optional": true
},
"wiki-security-social": {
"optional": true
}
},
"engines": {
"node": ">=14.0.0"
-6
View File
@@ -1,6 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}