From 11ea7e41795e8366d76fde8d9f85e2296a30bc57 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 11 Feb 2024 15:56:24 +0530 Subject: [PATCH] feat: socketio using authorization headers Earlier socketio only worked in browser where browser would send cookie (cause same domain) and hence socketio server used it to auth connection. This however is limited and doesn't allow simply creating socket connection from apps. Authorization headers on other hand are simple to implement. --- realtime/handlers/frappe_handlers.js | 11 +++-------- realtime/middlewares/authenticate.js | 19 ++++++++++++------- realtime/utils.js | 12 ++++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/realtime/handlers/frappe_handlers.js b/realtime/handlers/frappe_handlers.js index 923c0858b4..d56090ffb2 100644 --- a/realtime/handlers/frappe_handlers.js +++ b/realtime/handlers/frappe_handlers.js @@ -1,5 +1,4 @@ -const request = require("superagent"); -const { get_url } = require("../utils"); +const { frappe_request } = require("../utils"); const log = console.log; const WEBSITE_ROOM = "website"; @@ -114,11 +113,9 @@ function notify_disconnected_documents(socket) { function can_subscribe_doctype(args) { if (!args) return; if (!args.doctype) return; - request - .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doctype")) + frappe_request("/api/method/frappe.realtime.can_subscribe_doctype", args.socket) .type("form") .query({ - sid: args.socket.sid, doctype: args.doctype, }) .end(function (err, res) { @@ -166,11 +163,9 @@ function notify_subscribed_doc_users(args) { function can_subscribe_doc(args) { if (!args) return; if (!args.doctype || !args.docname) return; - request - .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doc")) + frappe_request("/api/method/frappe.realtime.can_subscribe_doc", args.socket) .type("form") .query({ - sid: args.socket.sid, doctype: args.doctype, docname: args.docname, }) diff --git a/realtime/middlewares/authenticate.js b/realtime/middlewares/authenticate.js index 6d81cd2e15..1bce8bb011 100644 --- a/realtime/middlewares/authenticate.js +++ b/realtime/middlewares/authenticate.js @@ -24,22 +24,27 @@ function authenticate_with_frappe(socket, next) { } let cookies = cookie.parse(socket.request.headers.cookie); + let authorization_header = socket.request.headers.authorization; - if (!cookies.sid) { - next(new Error("No sid transmitted.")); + if (!cookies.sid && !authorization_header) { + next(new Error("No authentication method used. Use cookie or authorization header.")); return; } - request - .get(get_url(socket, "/api/method/frappe.realtime.get_user_info")) + let auth_req = request.get(get_url(socket, "/api/method/frappe.realtime.get_user_info")); + if (cookies.sid) { + auth_req = auth_req.query({ sid: cookies.sid }); + } else { + auth_req = auth_req.set("Authorization", authorization_header); + } + + auth_req .type("form") - .query({ - sid: cookies.sid, - }) .then((res) => { socket.user = res.body.message.user; socket.user_type = res.body.message.user_type; socket.sid = cookies.sid; + socket.authorization_header = authorization_header; next(); }) .catch((e) => { diff --git a/realtime/utils.js b/realtime/utils.js index 89bb00c98e..04a2470e5e 100644 --- a/realtime/utils.js +++ b/realtime/utils.js @@ -1,5 +1,6 @@ const { get_conf } = require("../node_utils"); const conf = get_conf(); +const request = require("superagent"); function get_url(socket, path) { if (!path) { @@ -16,6 +17,17 @@ function get_url(socket, path) { return url + path; } +// Authenticates a partial request created using superagent +function frappe_request(path, socket) { + const partial_req = request.get(get_url(socket, path)); + if (socket.sid) { + return partial_req.query({ sid: socket.sid }); + } else if (socket.authorization_header) { + return partial_req.set("Authorization", socket.authorization_header); + } +} + module.exports = { get_url, + frappe_request, };