UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

218 lines (217 loc) 11.6 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "SyncClientsManager", { enumerable: true, get: function() { return SyncClientsManager; } }); const _axios = require("@nestjs/axios"); const _common = require("@nestjs/common"); const _nodecrypto = /*#__PURE__*/ _interop_require_default(require("node:crypto")); const _promises = /*#__PURE__*/ _interop_require_default(require("node:fs/promises")); const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path")); const _authmethod = require("../../../authentication/models/auth-method"); const _authmanagerservice = require("../../../authentication/services/auth-manager.service"); const _functions = require("../../../common/functions"); const _shared = require("../../../common/shared"); const _configconstants = require("../../../configuration/config.constants"); const _configenvironment = require("../../../configuration/config.environment"); const _cachedecorator = require("../../../infrastructure/cache/cache.decorator"); const _applicationsconstants = require("../../applications.constants"); const _files = require("../../files/utils/files"); const _user = require("../../users/constants/user"); const _usermodel = require("../../users/models/user.model"); const _usersqueriesservice = require("../../users/services/users-queries.service"); const _auth = require("../constants/auth"); const _store = require("../constants/store"); const _sync = require("../constants/sync"); const _syncqueriesservice = require("./sync-queries.service"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } let SyncClientsManager = class SyncClientsManager { async register(clientRegistrationDto, ip) { const user = await this.authMethod.validateUser(clientRegistrationDto.login, clientRegistrationDto.password); if (!user) { this.logger.warn(`${this.register.name} - auth failed for user *${clientRegistrationDto.login}*`); throw new _common.HttpException('Not authorized', _common.HttpStatus.UNAUTHORIZED); } if (!user.havePermission(_user.USER_PERMISSION.DESKTOP_APP)) { this.logger.warn(`${this.register.name} - does not have permission : ${_user.USER_PERMISSION.DESKTOP_APP}`); throw new _common.HttpException('Missing permission', _common.HttpStatus.FORBIDDEN); } try { const token = await this.syncQueries.getOrCreateClient(user.id, clientRegistrationDto.clientId, clientRegistrationDto.info, ip); this.logger.log(`${this.register.name} - client *${clientRegistrationDto.info.type}* was registered for user *${user.login}* (${user.id})`); return { clientToken: token }; } catch (e) { this.logger.error(`${this.register.name} - ${e}`); throw new _common.HttpException('Error during the client registration', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async unregister(user) { try { await this.syncQueries.deleteClient(user.id, user.clientId); } catch (e) { this.logger.error(`${this.unregister.name} - ${e}`); throw new _common.HttpException('Error during the removing of client registration', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async authenticate(authType, syncClientAuthDto, ip, res) { const client = await this.syncQueries.getClient(syncClientAuthDto.clientId, null, syncClientAuthDto.token); if (!client) { throw new _common.HttpException('Client is unknown', _common.HttpStatus.FORBIDDEN); } if (!client.enabled) { throw new _common.HttpException('Client is disabled', _common.HttpStatus.FORBIDDEN); } if ((0, _shared.currentTimeStamp)() >= client.tokenExpiration) { throw new _common.HttpException(_auth.CLIENT_TOKEN_EXPIRED_ERROR, _common.HttpStatus.FORBIDDEN); } this.syncQueries.updateClientInfo(client, client.info, ip).catch((e)=>this.logger.error(`${this.authenticate.name} - ${e}`)); const user = await this.usersQueries.from(client.ownerId); if (!user) { throw new _common.HttpException('User does not exist', _common.HttpStatus.FORBIDDEN); } if (!user.isActive) { throw new _common.HttpException('Account suspended or not authorized', _common.HttpStatus.FORBIDDEN); } const owner = new _usermodel.UserModel(user); if (!owner.havePermission(_user.USER_PERMISSION.DESKTOP_APP)) { this.logger.warn(`${this.register.name} - does not have permission : ${_user.USER_PERMISSION.DESKTOP_APP}`); throw new _common.HttpException('Missing permission', _common.HttpStatus.FORBIDDEN); } // set clientId owner.clientId = client.id; // update accesses this.usersQueries.updateUserOrGuest(owner.id, { lastAccess: owner.currentAccess, currentAccess: new Date(), lastIp: owner.currentIp, currentIp: ip }).catch((e)=>this.logger.error(`${this.authenticate.name} - ${e}`)); let r; if (authType === _auth.CLIENT_AUTH_TYPE.COOKIE) { // used by the desktop app to perform the login setup using cookies r = await this.authManager.setCookies(owner, res); } else if (authType === _auth.CLIENT_AUTH_TYPE.TOKEN) { // used by the cli app and the sync core r = await this.authManager.getTokens(owner); } // check if the client token must be updated r.client_token_update = await this.renewTokenAndExpiration(client, owner); return r; } getClients(user) { return this.syncQueries.getClients(user); } async renewTokenAndExpiration(client, owner) { if ((0, _shared.currentTimeStamp)() + (0, _functions.convertHumanTimeToSeconds)(_auth.CLIENT_TOKEN_RENEW_TIME) < client.tokenExpiration) { // client token expiration is not close enough return undefined; } const token = _nodecrypto.default.randomUUID(); const expiration = (0, _shared.currentTimeStamp)() + (0, _functions.convertHumanTimeToSeconds)(_auth.CLIENT_TOKEN_EXPIRATION_TIME); this.logger.log(`${this.renewTokenAndExpiration.name} - renew token for user *${owner.login}* and client *${client.id}*`); try { await this.syncQueries.renewClientTokenAndExpiration(client.id, token, expiration); } catch (e) { this.logger.error(`${this.renewTokenAndExpiration.name} - unable to renew token for user *${owner.login}* and client *${client.id}* : ${e}`); throw new _common.HttpException('Unable to update client token', _common.HttpStatus.BAD_REQUEST); } return token; } async deleteClient(user, clientId) { try { await this.syncQueries.deleteClient(user.id, clientId); } catch (e) { this.logger.error(`${this.deleteClient.name} - ${e}`); throw new _common.HttpException('Unable to delete client', _common.HttpStatus.INTERNAL_SERVER_ERROR); } } async checkAppStore() { let manifest = null; if (_configenvironment.configuration.applications.appStore.repository === _store.APP_STORE_REPOSITORY.PUBLIC) { const url = `${_store.APP_STORE_URL}/${_store.APP_STORE_MANIFEST_FILE}`; try { const res = await this.http.axiosRef({ method: _applicationsconstants.HTTP_METHOD.GET, url: url }); manifest = res.data; manifest.repository = _store.APP_STORE_REPOSITORY.PUBLIC; } catch (e) { this.logger.warn(`${this.checkAppStore.name} - unable to retrieve ${url} : ${e}`); } } else { const latestFile = _nodepath.default.join(_configconstants.STATIC_PATH, _store.APP_STORE_DIRNAME, _store.APP_STORE_MANIFEST_FILE); if (!await (0, _files.isPathExists)(latestFile)) { this.logger.warn(`${this.checkAppStore.name} - ${latestFile} does not exist`); } else { try { manifest = JSON.parse(await _promises.default.readFile(latestFile, 'utf8')); manifest.repository = _store.APP_STORE_REPOSITORY.LOCAL; // rewrite urls to local repository for (const [os, packages] of Object.entries(manifest.platform)){ for (const p of packages){ if (p.package.toLowerCase().startsWith(_sync.SYNC_CLIENT_TYPE.DESKTOP)) { p.url = `${_store.APP_STORE_DIRNAME}/${_sync.SYNC_CLIENT_TYPE.DESKTOP}/${os}/${p.package}`; } else { p.url = `${_store.APP_STORE_DIRNAME}/${_sync.SYNC_CLIENT_TYPE.CLI}/${p.package}`; } } } } catch (e) { this.logger.error(`${this.checkAppStore.name} - ${latestFile} : ${e}`); } } } return manifest; } constructor(http, authManager, authMethod, usersQueries, syncQueries){ this.http = http; this.authManager = authManager; this.authMethod = authMethod; this.usersQueries = usersQueries; this.syncQueries = syncQueries; this.logger = new _common.Logger(SyncClientsManager.name); } }; _ts_decorate([ (0, _cachedecorator.CacheDecorator)(3600), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", []), _ts_metadata("design:returntype", Promise) ], SyncClientsManager.prototype, "checkAppStore", null); SyncClientsManager = _ts_decorate([ (0, _common.Injectable)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _axios.HttpService === "undefined" ? Object : _axios.HttpService, typeof _authmanagerservice.AuthManager === "undefined" ? Object : _authmanagerservice.AuthManager, typeof _authmethod.AuthMethod === "undefined" ? Object : _authmethod.AuthMethod, typeof _usersqueriesservice.UsersQueries === "undefined" ? Object : _usersqueriesservice.UsersQueries, typeof _syncqueriesservice.SyncQueries === "undefined" ? Object : _syncqueriesservice.SyncQueries ]) ], SyncClientsManager); //# sourceMappingURL=sync-clients-manager.service.js.map