mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-13 01:32:10 +00:00
fix: socket io sockets (#2696)
This commit is contained in:
Generated
+1
-1
@@ -24422,7 +24422,7 @@
|
||||
},
|
||||
"src/puter-js": {
|
||||
"name": "@heyputer/puter.js",
|
||||
"version": "2.2.12",
|
||||
"version": "2.2.14",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@heyputer/kv.js": "^0.2.1",
|
||||
|
||||
@@ -1546,7 +1546,7 @@ export function subdomain (req) {
|
||||
return req.hostname.slice(0, -1 * (config.domain.length + 1));
|
||||
}
|
||||
|
||||
export async function jwt_auth (req) {
|
||||
export async function jwt_auth (req, authService) {
|
||||
let token;
|
||||
// HTTML Auth header
|
||||
if ( req.header && req.header('Authorization') )
|
||||
@@ -1583,8 +1583,11 @@ export async function jwt_auth (req) {
|
||||
}
|
||||
|
||||
try {
|
||||
const svc_auth = Context.get('services').get('auth');
|
||||
const actor = await svc_auth.authenticate_from_token(token);
|
||||
if ( ! authService ) {
|
||||
throw new Error('jwt_auth requires authService');
|
||||
}
|
||||
|
||||
const actor = await authService.authenticate_from_token(token);
|
||||
|
||||
if ( !actor.type?.constructor?.name === 'UserActorType' ) {
|
||||
throw ({
|
||||
|
||||
@@ -66,9 +66,7 @@ class SocketioService extends BaseService {
|
||||
if ( socket_specifier.room ) {
|
||||
this.io.to(socket_specifier.room).emit(key, data);
|
||||
} else if ( socket_specifier.socket ) {
|
||||
const io = this.io.sockets.sockets.get(socket_specifier.socket);
|
||||
if ( ! io ) continue;
|
||||
io.emit(key, data);
|
||||
this.io.to(socket_specifier.socket).emit(key, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,27 +260,36 @@ class WebServerService extends BaseService {
|
||||
// TODO: ^ Replace above line with the following code:
|
||||
await this.services.emit('install.socketio', { server });
|
||||
const socketio = this.services.get('socketio').io;
|
||||
const authService = this.services.get('auth');
|
||||
|
||||
// Socket.io middleware for authentication
|
||||
socketio.use(async (socket, next) => {
|
||||
if ( socket.handshake.auth.auth_token ) {
|
||||
try {
|
||||
let auth_res = await jwt_auth(socket);
|
||||
// successful auth
|
||||
socket.actor = auth_res.actor;
|
||||
socket.user = auth_res.user;
|
||||
socket.token = auth_res.token;
|
||||
// join user room
|
||||
socket.join(socket.user.id);
|
||||
const authToken = socket.handshake?.auth?.auth_token;
|
||||
if ( ! authToken ) {
|
||||
next(new Error('socket auth token missing'));
|
||||
return;
|
||||
}
|
||||
|
||||
// setTimeout 0 is needed because we need to send
|
||||
// the notifications after this handler is done
|
||||
// setTimeout(() => {
|
||||
// }, 1000);
|
||||
next();
|
||||
} catch (e) {
|
||||
console.warn('socket auth err', e);
|
||||
}
|
||||
try {
|
||||
const authRes = await jwt_auth(socket, authService);
|
||||
// successful auth
|
||||
socket.actor = authRes.actor;
|
||||
socket.user = authRes.user;
|
||||
socket.token = authRes.token;
|
||||
// join user room
|
||||
socket.join(socket.user.id);
|
||||
|
||||
// setTimeout 0 is needed because we need to send
|
||||
// the notifications after this handler is done
|
||||
// setTimeout(() => {
|
||||
// }, 1000);
|
||||
next();
|
||||
} catch ( error ) {
|
||||
console.warn('socket auth err', error);
|
||||
const authError = error instanceof Error
|
||||
? error
|
||||
: new Error('socket auth failed');
|
||||
next(authError);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -674,6 +683,16 @@ class WebServerService extends BaseService {
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
const origin = req.headers.origin;
|
||||
const subdomain = req.subdomains[req.subdomains.length - 1];
|
||||
const isApiOrDavRequest =
|
||||
config.experimental_no_subdomain ||
|
||||
subdomain === 'api' ||
|
||||
subdomain === 'dav';
|
||||
const isCrossOriginAuthRoute =
|
||||
req.path === '/signup' ||
|
||||
req.path === '/login' ||
|
||||
req.path.startsWith('/extensions/') ||
|
||||
req.path.startsWith('/auth/oidc');
|
||||
|
||||
const is_site =
|
||||
hostMatchesDomain(req.hostname, config.static_hosting_domain) ||
|
||||
@@ -692,16 +711,16 @@ class WebServerService extends BaseService {
|
||||
req.co_isolation_enabled
|
||||
;
|
||||
|
||||
if ( req.path === '/signup' || req.path === '/login' || req.path.startsWith('/extensions/') || req.path.startsWith('/auth/oidc') ) {
|
||||
if ( isCrossOriginAuthRoute || isApiOrDavRequest ) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin ?? '*');
|
||||
if ( origin ) {
|
||||
res.vary('Origin');
|
||||
}
|
||||
}
|
||||
// Website(s) to allow to connect
|
||||
if (
|
||||
config.experimental_no_subdomain ||
|
||||
req.subdomains[req.subdomains.length - 1] === 'api' ||
|
||||
req.subdomains[req.subdomains.length - 1] === 'dav'
|
||||
) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin ?? '*');
|
||||
|
||||
// Allow browser credentials on API/DAV cross-origin requests.
|
||||
if ( isApiOrDavRequest && origin ) {
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
|
||||
// Request methods to allow
|
||||
@@ -715,10 +734,6 @@ class WebServerService extends BaseService {
|
||||
// Request headers to allow
|
||||
res.header('Access-Control-Allow-Headers', allowed_headers.join(', '));
|
||||
|
||||
// Set to true if you need the website to include cookies in the requests sent
|
||||
// to the API (e.g. in case you use sessions)
|
||||
// res.setHeader('Access-Control-Allow-Credentials', true);
|
||||
|
||||
// Needed for SharedArrayBuffer
|
||||
// NOTE: This is put behind a configuration flag because we
|
||||
// need some experimentation to ensure the interface
|
||||
|
||||
@@ -113,6 +113,7 @@ router.all('*', async function (req, res, next) {
|
||||
}
|
||||
|
||||
const db = Context.get('services').get('database').get(DB_READ, 'default');
|
||||
const authService = Context.get('services').get('auth');
|
||||
|
||||
// --------------------------------------
|
||||
// POST to login/signup/logout
|
||||
@@ -137,7 +138,7 @@ router.all('*', async function (req, res, next) {
|
||||
let authed = false;
|
||||
try {
|
||||
try {
|
||||
auth_user = await jwt_auth(req);
|
||||
auth_user = await jwt_auth(req, authService);
|
||||
auth_user = auth_user.user;
|
||||
authed = true;
|
||||
} catch (e) {
|
||||
|
||||
@@ -34,14 +34,22 @@ class WSPushService extends BaseService {
|
||||
this.svc_event.on('fs.write.*', this._on_fs_update.bind(this));
|
||||
this.svc_event.on('fs.move.*', this._on_fs_move.bind(this));
|
||||
this.svc_event.on('fs.pending.*', this._on_fs_pending.bind(this));
|
||||
this.svc_event.on('fs.storage.upload-progress',
|
||||
this._on_upload_progress.bind(this));
|
||||
this.svc_event.on('fs.storage.progress.*',
|
||||
this._on_upload_progress.bind(this));
|
||||
this.svc_event.on('puter-exec.submission.done',
|
||||
this._on_submission_done.bind(this));
|
||||
this.svc_event.on('outer.gui.*',
|
||||
this._on_outer_gui.bind(this));
|
||||
this.svc_event.on(
|
||||
'fs.storage.upload-progress',
|
||||
this._on_upload_progress.bind(this),
|
||||
);
|
||||
this.svc_event.on(
|
||||
'fs.storage.progress.*',
|
||||
this._on_upload_progress.bind(this),
|
||||
);
|
||||
this.svc_event.on(
|
||||
'puter-exec.submission.done',
|
||||
this._on_submission_done.bind(this),
|
||||
);
|
||||
this.svc_event.on(
|
||||
'outer.gui.*',
|
||||
this._on_outer_gui.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
async _on_fs_create (key, data) {
|
||||
@@ -251,16 +259,12 @@ class WSPushService extends BaseService {
|
||||
const { socket_id } = metadata;
|
||||
|
||||
if ( ! socket_id ) {
|
||||
this.log.warn('missing socket id', { metadata });
|
||||
}
|
||||
|
||||
this.log.info(`socket id: ${ socket_id}`);
|
||||
|
||||
const svc_socketio = context.get('services').get('socketio');
|
||||
if ( ! svc_socketio.has({ socket: socket_id }) ) {
|
||||
console.warn('missing socket id', { metadata });
|
||||
return;
|
||||
}
|
||||
|
||||
const svc_socketio = context.get('services').get('socketio');
|
||||
|
||||
const ws_event_name = metadata.call_it_download
|
||||
? 'download.progress' : 'upload.progress';
|
||||
|
||||
@@ -311,9 +315,6 @@ class WSPushService extends BaseService {
|
||||
const svc_socketio = this.services.get('socketio');
|
||||
|
||||
for ( const user_id of user_id_list ) {
|
||||
if ( ! svc_socketio.has({ room: user_id }) ) {
|
||||
continue;
|
||||
}
|
||||
svc_socketio.send({ room: user_id }, key, response);
|
||||
this.svc_event.emit(`sent-to-user.${key}`, {
|
||||
user_id,
|
||||
@@ -340,7 +341,7 @@ class WSPushService extends BaseService {
|
||||
const kvStore = Context.get('services').get('puter-kvstore');
|
||||
await kvStore.set({ key: key, value: ts });
|
||||
} catch ( error ) {
|
||||
this.log.error('Failed to update user timestamp in kvstore', { user_id, error: error.message });
|
||||
console.error('Failed to update user timestamp in kvstore', { user_id, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ const download = function (options) {
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open('post', (`${window.api_origin }/download`), true);
|
||||
xhr.withCredentials = true;
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${ window.auth_token}`);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "puter",
|
||||
"version": "2.2.12",
|
||||
"version": "2.2.14",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "puter",
|
||||
"version": "2.2.12",
|
||||
"version": "2.2.14",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@heyputer/kv.js": "^0.1.92",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@heyputer/puter.js",
|
||||
"version": "2.2.12",
|
||||
"version": "2.2.14",
|
||||
"description": "Puter.js - A JavaScript library for interacting with Puter services.",
|
||||
"homepage": "https://developer.puter.com",
|
||||
"main": "src/index.js",
|
||||
|
||||
@@ -92,6 +92,7 @@ const createDeferred = () => {
|
||||
function initXhr (endpoint, APIOrigin, authToken, method = 'post', contentType = 'text/plain;actually=json', responseType = undefined) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, APIOrigin + endpoint, true);
|
||||
xhr.withCredentials = true;
|
||||
if ( authToken )
|
||||
{
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${ authToken}`);
|
||||
@@ -280,16 +281,18 @@ function make_driver_method (arg_defs, driverInterface, driverName, driverMethod
|
||||
async function driverCall (options, driverInterface, driverName, driverMethod, driverArgs, settings) {
|
||||
const deferred = createDeferred();
|
||||
|
||||
driverCall_(options,
|
||||
deferred.resolve,
|
||||
deferred.reject,
|
||||
driverInterface,
|
||||
driverName,
|
||||
driverMethod,
|
||||
driverArgs,
|
||||
undefined,
|
||||
undefined,
|
||||
settings);
|
||||
driverCall_(
|
||||
options,
|
||||
deferred.resolve,
|
||||
deferred.reject,
|
||||
driverInterface,
|
||||
driverName,
|
||||
driverMethod,
|
||||
driverArgs,
|
||||
undefined,
|
||||
undefined,
|
||||
settings,
|
||||
);
|
||||
|
||||
return await deferred.promise;
|
||||
}
|
||||
@@ -297,8 +300,12 @@ async function driverCall (options, driverInterface, driverName, driverMethod, d
|
||||
// This function encapsulates the logic for sending a driver call request
|
||||
async function driverCall_ (
|
||||
options = {},
|
||||
resolve_func, reject_func,
|
||||
driverInterface, driverName, driverMethod, driverArgs,
|
||||
resolve_func,
|
||||
reject_func,
|
||||
driverInterface,
|
||||
driverName,
|
||||
driverMethod,
|
||||
driverArgs,
|
||||
method,
|
||||
contentType = 'text/plain;actually=json',
|
||||
settings = {},
|
||||
|
||||
@@ -457,6 +457,7 @@ const upload = async function (items, dirPath, options = {}) {
|
||||
|
||||
// open request to server
|
||||
xhr.open('post', (`${this.APIOrigin }/batch`), true);
|
||||
xhr.withCredentials = true;
|
||||
// set auth header
|
||||
xhr.setRequestHeader('Authorization', `Bearer ${ this.authToken}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user