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.
This commit is contained in:
Ankush Menat 2024-02-11 15:56:24 +05:30
parent 17ebc5ee4d
commit 11ea7e4179
3 changed files with 27 additions and 15 deletions

View file

@ -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,
})

View file

@ -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) => {

View file

@ -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,
};