File: /volume1/@appstore/Spreadsheet/server/common/base/app.js
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"default",{enumerable:true,get:function(){return m}});const e=h(require("../webapi"));const t=require("@synology-office/logger");const s=require("../helper");const i=require("../../task-daemon/send-metric");const r=h(require("../usergroup"));const n=h(require("./action-info"));const c=h(require("../SynoSocket"));const o=require("../../cluster");const a=require("../helper/cluster");function h(e){return e&&e.__esModule?e:{default:e}}const l=5e3;const f=3e4;class u{constructor(e){this.ioServer=new c.default(e,this.getNType(),{authSuccess:this.onAuthSuccess.bind(this),connection:this.onConnect.bind(this)});this.usergroup=new r.default;this.instanceStore=this.createInstanceStore();this.objectIdsToCheckPerm=new Set;this.uidsToCheckPerm=new Set;this.checkPermTimer=null;this.checkUserPermTimer=null}async initInstance(e,t){let s;const i=this.instanceStore.getInstance(e);if(i){if(i.isDestroying()){await i.waitDestroying()}else{s=i}}if(!s){s=this.instanceStore.getInstance(e,true)}if(t){s.setPassword(t.password);s.setFileInfo(t.file_info)}return s}getInstance(e){return this.instanceStore.getInstance(e)}removeInstance(e){this.instanceStore.remove(e)}onAuthSuccess(e,t){if(!t.writable&&!t.readable&&!t.previewable){return false}return true}initUserRecord(e){this.usergroup.upsertUserName(e.uid,e.username,0)}getUserRecord(e){return this.usergroup.getUser(e)}async fetchUserRecord(e){try{return await this.usergroup.fetchUser(e)}catch(s){t.logger.error("fetchUserRecord failed",e,s);return this.usergroup.getUser(e)}}fetchUserGroup(e,t,s,i){this.usergroup.fetchUserGroup(e,t,s).then((({users:e,groups:t})=>{i(true,e,t)})).catch((()=>{i(false)}))}reload(e,t){e.forEach((e=>{const s=this.getInstance(e);if(!s){return}let i=false;let r=false;if(t){if(t.password){r=s.getPassword()!==t.password;s.setPassword(t.password)}if(true===t.synodrive){i=true}}const n=s.broadcastAll.bind(s,"reload",!r);if(true===i){this.reloadData(e).catch((()=>{})).then(n)}else{n()}}))}kick(e,{reason:t,userFilter:s=(()=>true),excludeSharing:i=false}={}){function r(e){if(i&&e.getSharingLink()){return}if(!s(e.getUid())){return}if(t==="delete"){const{removed:t}=e.getFileCacheInfo();if(t){return}e.setFileRemoved(true)}e.kick(t)}for(const s of e){const e=this.getInstance(s);if(e){e.listClients().forEach(r);if("delete"===t){e.setRemoved(true)}}}if("delete"===t){this.flush(e)}}setInfo(e,t,s){if(!s){return}for(const i of e){const e=this.getInstance(i);if(!e){continue}if(s.name){e.updateName(s.name)}const r=t!==undefined;for(const i of e.listClients()){if(r&&i.getUid()!==t){continue}if(!this.checkClientCacheInfo(i,i.getFileCacheInfo(),s)){i.emit("set_info",s)}}}}getInfo(e){const t=this.getInstance(e);if(!t){return null}return{pass:t.getPassword()||""}}onKickPath(e){if(!this.getAllObjectIds().some(s.isFile)){return}const t=this._getObjectIdsByActionUnits(e);if(0===t.length){return}this.kick(t)}onCheckPath(e){if(!this.getAllObjectIds().some(s.isFile)){return}const t=function(e,t,s){if(s){t=t.filter((e=>s!==e))}for(const s of t){e.add(s)}};const i=new Set;e.forEach((e=>{const s=e.object_id;switch(e.event_type){case"file_modified":case"file_shared":case"file_moved":case"file_restored":t(i,this._getObjectIdsByActionUnit(e));if(s){i.add(s)}break;case"file_renamed":case"file_created":case"file_copied":t(i,this._getObjectIdsByActionUnit(e),e.object_id);break;case"file_removed":this.kick(s?[s]:this._getObjectIdsByActionUnit(e),{reason:"delete"});break;default:break}switch(e.event_type){case"file_moved":case"file_renamed":this.onUpdatePath(e);break;case"file_restored":if(s){const t=this.getInstance(s);if(t){t.setPath(e.path)}}break;default:break}}));this.onCheckPerm(Array.from(i))}onUpdatePath(e){const t=this._getObjectIdsByActionUnit(e);if(0===t.length){return}for(const s of t){const t=this.getInstance(s);if(!t||!e.ori_path||!e.path){continue}t.updatePath(e.ori_path,e.path)}}_getObjectIdsByActionUnit(e){return this._getObjectIdsByActionUnits([e])}_getObjectIdsByActionUnits(e){const t=new n.default(e);const s=[];this.instanceStore.forEach(((e,i)=>{if(e.isRemoved()){return}const r=e.getPath();if(!r){return}if(t.has(r)){s.push(i)}}));return s}_getClientsBySharingLink(e){const t=[];this.instanceStore.forEach((s=>{for(const i of s.listClients()){if(e===i.getSharingLink()){t.push(i)}}}));return t}onCheckSharingLink(e){for(const t of e){for(const e of this._getClientsBySharingLink(t.sharing_link)){const i=t;if((0,s.isPermissionNone)(i)){e.kick()}else if(t.reload||(0,s.isPermissionUpgrade)(e.getPermission(),i)||(0,s.isPermissionDowngrade)(e.getPermission(),i)){e.emit("reload")}}}}onKickSharingLink(e){for(const t of e){for(const e of this._getClientsBySharingLink(t.sharing_link)){e.kick()}}}onCheckPerm(e){for(const t of e){this.objectIdsToCheckPerm.add(t)}this._execCheckPermDefer("normal")}onCheckPermAll(){this.uidsToCheckPerm=new Set;this._cancelCheckUserPermDefer();this.objectIdsToCheckPerm=new Set(this.getAllObjectIds());this._execCheckPermDefer("all")}onCheckUserPerm(e){for(const t of e){this.uidsToCheckPerm.add(t)}this._execCheckUserPermDefer()}willCheckAllPerm(){return this.checkPermTimer?.type==="all"}_execCheckPermDefer(e){if(this.checkPermTimer){if(e==="normal"&&this.willCheckAllPerm()){clearTimeout(this.checkPermTimer.id);this.checkPermTimer=null;this._execCheckPermDefer("all")}return}const s=setTimeout((async()=>{this.checkPermTimer=null;try{const t=e==="all";const s=this.objectIdsToCheckPerm;this.objectIdsToCheckPerm=new Set;await this._validatePermissionAsync(s,t)}catch(e){t.logger.error("failed to check perm",e)}}),e==="all"?f:l);this.checkPermTimer={id:s,type:e}}_execCheckUserPermDefer(){this._cancelCheckUserPermDefer();this.checkUserPermTimer=setTimeout((()=>this._execCheckUserPerm()),f)}_cancelCheckUserPermDefer(){if(this.checkUserPermTimer){clearTimeout(this.checkUserPermTimer);this.checkUserPermTimer=null}}getAllObjectIds(){return this.instanceStore.all()}getValidationClients(e){const t=this.getInstance(e);return t?t.listClients():[]}_validatePermissionAsync(e,t,s=(()=>true)){const i=[];const r=[];for(const n of e){const e=this.getValidationClients(n).filter(s);const c=new Map;const o=new Map;for(const s of e){const e=s.getUid();const i=s.getSharingLink();const r=new d(t,e,s.getRemoteIP(),i);const n=r.getKey();if(i){if(!o.has(n)){o.set(n,r)}}else if(e!==undefined){if(!c.has(n)){c.set(n,r)}}}if(c.size>0||o.size>0){const t=e[0].getLinkId();i.push({object_id:n,link_id:t,user:Array.from(c.values()),sharing_link:Array.from(o.values())});r.push(e)}}return this._checkRoomUsersPerm(i,r,t)}_execCheckUserPerm(){const e=this.uidsToCheckPerm;this.uidsToCheckPerm=new Set;if(this.willCheckAllPerm()){return Promise.resolve()}return this._validatePermissionAsync(this.getAllObjectIds(),true,(t=>e.has(t.getUid())&&!t.getSharingLink()))}async _checkRoomUsersPerm(s,i,r){if(s.length===0){return}try{const t=await e.default.root.run({api:"SYNO.Office.Permission.User",method:"check",version:1,room:s,checkapp:r});t.forEach(((e,t)=>{const s=i[t];if(e===null||!s){return}this._checkClientsState(s,r,e.file_info,e.perms,e.users)}))}catch(e){t.logger.error("Failed to reValidate permission ",e)}}_checkClientsState(e,t,i,r,n){const c=[];for(const o of e){if(!o.isConnected()){continue}let e=true;if(i){const t=o.getObjectId();const{removed:r,name:a,path:h}=i;if((0,s.isFile)(t)&&h){const e=this.getInstance(t);if(e){e.setPath(h);e.setRemoved(r)}}const l=o.getFileCacheInfo();if(l.removed&&!r){c.push(o);e=false}else if(!l.removed&&r){this.flush([t]);if(o.isConnected()){o.setFileRemoved(true);o.kick("delete")}e=false}else{let e;if(n){e=n[o.getUid()]?.star}this.checkClientCacheInfo(o,l,{name:a,star:e})}}if(e){this._checkFilePerms(o,t,r)}}if(c.length>0){this.flush([c[0].getObjectId()]).then((()=>this.afterDocUndelete(c)))}}checkClientCacheInfo(e,t,s){let i=false;if(s.name&&t.name!==s.name){i=true;e.setFileName(s.name)}let r=false;if("boolean"===typeof s.star&&t.star!==s.star){r=true;e.setStar(s.star)}if(i||r){e.emit("set_info",s);return true}return false}afterDocUndelete(e){for(const t of e){if(t.isConnected()){t.setFileRemoved(false);t.emit("reload")}}}_checkFilePerms(e,t,i){let r;if(i){const t=e.getSharingLink();if(t){if(i.sharing_link){r=i.sharing_link[t]}}else if(i.users){r=i.users[e.getUid()]}}if(!r||(0,s.isPermissionNone)(r)){e.kick()}else if((0,s.isPermissionUpgrade)(e.getPermission(),r)||(0,s.isPermissionDowngrade)(e.getPermission(),r)){e.emit("reload")}else if(t&&r.deny_ip&&-1!==r.deny_ip.indexOf(e.getRemoteIP())){e.kick()}}flushFull(e={}){const t=[];this.instanceStore.forEach(((i,r)=>{let n=true;if(e&&e.basePath&&!i.isRemoved()){const t=i.getPath();n=!!t&&(0,s.isSubPath)(e.basePath,t)}if(n){t.push(r)}}));return this.flush(t)}getUserPass(e){const t=this.getInstance(e);return t&&t.getPassword()||""}stat(e,t){const s=[];this.instanceStore.forEach(((e,t)=>{const i=e.listClients(false).map((e=>e.getUid()));s.push([t,i])}));t(s)}sendMetric(e,t,s){(0,i.sendMetric)(e,t,s).catch((()=>{}))}async onClusterUnlockByEvent(e){const t=this._getObjectIdsByActionUnits(e);if(0===t.length){return}const s=[];for(const e of t){const t=this.getInstance(e);if(!t){continue}s.push(t.forceDestroy("cluster_unlock"))}await Promise.allSettled(s)}async onClusterUnlockByPath(e){const t=[];this.instanceStore.forEach(((i,r)=>{const n=i.getPath();if(!e.some((e=>(0,s.isSubPath)(e,n)))){return}t.push(i.forceDestroy("cluster_unlock"))}));await Promise.allSettled(t)}async onClusterUnlockByObjectId(e,t){let i=this.getInstance(e);if(!i){await(new o.ClusterMgr).unlock({objectId:e});return}if((0,a.isFSDN)()){await i.forceDestroy("cluster_unlock");return}if((0,s.isTemplate)(e)){await this.onClusterUnlockTemplate()}else if(t){await(new o.ClusterMgr).clearPaths([t]).catch((()=>{}));await this.onClusterUnlockByPath([t])}i=this.getInstance(e);if(i){await i.forceDestroy("cluster_unlock")}}async onClusterUnlockByHostId(e){const t=[];this.instanceStore.forEach(((s,i)=>{if(e!==(0,a.getHostIDByObjectId)(i)){return}t.push(s.forceDestroy("cluster_unlock"))}));await Promise.allSettled(t)}async onClusterUnlockTemplate(){const e=[];this.instanceStore.forEach(((t,i)=>{if(!(0,s.isTemplate)(i)){return}e.push(t.forceDestroy("cluster_unlock"))}));await Promise.allSettled(e)}async onClusterRelock(){const e=[];this.instanceStore.forEach(((t,s)=>{e.push(t.lock(false).catch((()=>{t.forceDestroy()})))}));await Promise.all(e)}async onExit(){await this.instanceStore.destroyAll("app_stop")}}class d{constructor(e,t,s,i){this.uid=undefined;this.remoteIP=undefined;this.sharingLink=undefined;if(i){this.sharingLink=i}else{this.uid=t;if(e){this.remoteIP=s}}}getKey(){return[this.uid,this.remoteIP,this.sharingLink].join("/")}}const m=u;