openvibers/openvibe.chat Commits
Chat: Live's legacy token cookie authenticates nothing (C-05) (#72)
Changes
@@@ -35,20 +35,19 @@ function apiTokenAllows(req, scopes) {}/**-- * Extract the token and where it came from (Bearer header, the Network `ov_token` cookie, or Live's-- * legacy `token` cookie). Internal: extractToken returns the token alone.++ * Extract the token and where it came from: the Bearer header or the Network `ov_token` cookie. Live's legacy++ * `token` cookie is not read (Live no longer sets it; compatibility register C-05). Internal: extractToken returns++ * the token alone.*/--function extractTokenFrom(req, { legacyCookie = true } = {}) {++function extractTokenFrom(req) {const authHeader = req.headers.authorization;if (authHeader && authHeader.startsWith('Bearer ')) {return { token: authHeader.slice(7), from: 'header' };}-- // The Network session cookie is shared with the browser. REST still accepts Live's legacy-- // 'token' cookie (as Live does); WebSocket upgrades ignore it (legacyCookie: false).++ // The Network session cookie is shared with the browser.if (req.cookies) {if (req.cookies.ov_token) return { token: req.cookies.ov_token, from: 'ov_token_cookie' };-- if (legacyCookie && req.cookies.token) return { token: req.cookies.token, from: 'legacy_cookie' };}// Raw Node/WebSocket upgrade requests do not go through cookie-parser,@@@ -65,7 +64,6 @@ function extractTokenFrom(req, { legacyCookie = true } = {}) {try { parsed[key] = decodeURIComponent(value); } catch { parsed[key] = value; }}if (parsed.ov_token) return { token: parsed.ov_token, from: 'ov_token_cookie' };-- if (legacyCookie && parsed.token) return { token: parsed.token, from: 'legacy_cookie' };}return { token: null, from: null };@@@ -97,7 +95,7 @@ function extractWsToken(req) {* extractWsToken or its first message.*/function banExemptionToken(req) {-- return extractTokenFrom(req, { legacyCookie: false }).token;++ return extractTokenFrom(req).token;}/**nnew file mode 100644@@@ -0,0 +1,17 @@++'use strict';++// Compatibility register C-05: Chat reads the Bearer header and the Network `ov_token` cookie only. Live's legacy++// `token` cookie (the same token under another name; Live no longer sets it) authenticates nothing, on REST or on++// the ban-exemption check of a WebSocket upgrade.++const assert = require('assert');++const { extractToken, banExemptionToken } = require('../server/auth/auth');++++assert.strictEqual(extractToken({ headers: { authorization: 'Bearer bot' } }), 'bot');++assert.strictEqual(extractToken({ headers: {}, cookies: { ov_token: 'net' } }), 'net');++assert.strictEqual(extractToken({ headers: { cookie: 'ov_token=net' } }), 'net', 'the raw Cookie header (upgrades)');++assert.strictEqual(extractToken({ headers: {}, cookies: { token: 'legacy' } }), null, 'a lone legacy cookie authenticates nothing');++assert.strictEqual(extractToken({ headers: { cookie: 'token=legacy' } }), null, 'nor through the raw Cookie header');++assert.strictEqual(extractToken({ headers: {}, cookies: { token: 'legacy', ov_token: 'net' } }), 'net');++assert.strictEqual(banExemptionToken({ headers: { cookie: 'token=legacy' } }), null);++assert.strictEqual(banExemptionToken({ headers: { cookie: 'ov_token=net' } }), 'net');++++console.log('legacy token cookie: Chat reads the bearer and ov_token only — all checks passed');
@@ -35,20 +35,19 @@ function apiTokenAllows(req, scopes) {
@@ -35,20 +35,19 @@ function apiTokenAllows(req, scopes) {
}
}
/**
/**
- * Extract the token and where it came from (Bearer header, the Network `ov_token` cookie, or Live's
- * legacy `token` cookie). Internal: extractToken returns the token alone.
+ * Extract the token and where it came from: the Bearer header or the Network `ov_token` cookie. Live's legacy
+ * `token` cookie is not read (Live no longer sets it; compatibility register C-05). Internal: extractToken returns
+ * the token alone.
*/
*/
-function extractTokenFrom(req, { legacyCookie = true } = {}) {
+function extractTokenFrom(req) {
const authHeader = req.headers.authorization;
const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Bearer ')) {
if (authHeader && authHeader.startsWith('Bearer ')) {
return { token: authHeader.slice(7), from: 'header' };
return { token: authHeader.slice(7), from: 'header' };
}
}
- // The Network session cookie is shared with the browser. REST still accepts Live's legacy
- // 'token' cookie (as Live does); WebSocket upgrades ignore it (legacyCookie: false).
+ // The Network session cookie is shared with the browser.
if (req.cookies) {
if (req.cookies) {
if (req.cookies.ov_token) return { token: req.cookies.ov_token, from: 'ov_token_cookie' };
if (req.cookies.ov_token) return { token: req.cookies.ov_token, from: 'ov_token_cookie' };
- if (legacyCookie && req.cookies.token) return { token: req.cookies.token, from: 'legacy_cookie' };
}
}
// Raw Node/WebSocket upgrade requests do not go through cookie-parser,
// Raw Node/WebSocket upgrade requests do not go through cookie-parser,
@@ -65,7 +64,6 @@ function extractTokenFrom(req, { legacyCookie = true } = {}) {
@@ -65,7 +64,6 @@ function extractTokenFrom(req, { legacyCookie = true } = {}) {
try { parsed[key] = decodeURIComponent(value); } catch { parsed[key] = value; }
try { parsed[key] = decodeURIComponent(value); } catch { parsed[key] = value; }
}
}
if (parsed.ov_token) return { token: parsed.ov_token, from: 'ov_token_cookie' };
if (parsed.ov_token) return { token: parsed.ov_token, from: 'ov_token_cookie' };
- if (legacyCookie && parsed.token) return { token: parsed.token, from: 'legacy_cookie' };
}
}
return { token: null, from: null };
return { token: null, from: null };
@@ -97,7 +95,7 @@ function extractWsToken(req) {
@@ -97,7 +95,7 @@ function extractWsToken(req) {
* extractWsToken or its first message.
* extractWsToken or its first message.
*/
*/
function banExemptionToken(req) {
function banExemptionToken(req) {
- return extractTokenFrom(req, { legacyCookie: false }).token;
+ return extractTokenFrom(req).token;
}
}
/**
/**
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+'use strict';
+// Compatibility register C-05: Chat reads the Bearer header and the Network `ov_token` cookie only. Live's legacy
+// `token` cookie (the same token under another name; Live no longer sets it) authenticates nothing, on REST or on
+// the ban-exemption check of a WebSocket upgrade.
+const assert = require('assert');
+const { extractToken, banExemptionToken } = require('../server/auth/auth');
+
+assert.strictEqual(extractToken({ headers: { authorization: 'Bearer bot' } }), 'bot');
+assert.strictEqual(extractToken({ headers: {}, cookies: { ov_token: 'net' } }), 'net');
+assert.strictEqual(extractToken({ headers: { cookie: 'ov_token=net' } }), 'net', 'the raw Cookie header (upgrades)');
+assert.strictEqual(extractToken({ headers: {}, cookies: { token: 'legacy' } }), null, 'a lone legacy cookie authenticates nothing');
+assert.strictEqual(extractToken({ headers: { cookie: 'token=legacy' } }), null, 'nor through the raw Cookie header');
+assert.strictEqual(extractToken({ headers: {}, cookies: { token: 'legacy', ov_token: 'net' } }), 'net');
+assert.strictEqual(banExemptionToken({ headers: { cookie: 'token=legacy' } }), null);
+assert.strictEqual(banExemptionToken({ headers: { cookie: 'ov_token=net' } }), 'net');
+
+console.log('legacy token cookie: Chat reads the bearer and ov_token only — all checks passed');