File: //var/packages/WebStation/target/ui/webstation_utils.js
/* Copyright (c) 2026 Synology Inc. All rights reserved. */
Ext.ns("SYNO.SDS.WebStation.Errors"),SYNO.SDS.WebStation.Errors.GetMessage=function(t,a){let e=_T("error","error_error_system"),i={1004:_TT("SYNO.SDS.WebStation.Application","error","err_host_duplicated"),1007:_TT("SYNO.SDS.WebStation.Application","error","err_fqdn_invalid"),1008:_TT("SYNO.SDS.WebStation.Application","error","err_port_invalid"),1009:_TT("SYNO.SDS.WebStation.Application","error","err_port_conflict"),1015:_TT("SYNO.SDS.WebStation.Application","error","err_root_invalid"),1017:_TT("SYNO.SDS.WebStation.Application","error","err_php_invalid"),1018:_TT("SYNO.SDS.WebStation.Application","error","err_backend_invalid"),1021:_T("app_port_alias","err_fqdn_duplicated"),1022:_TT("SYNO.SDS.WebStation.Application","error","err_vhost_acl"),1207:_TT("SYNO.SDS.WebStation.Application","error","err_service_conflict"),1304:_TT("SYNO.SDS.WebStation.Application","error","bad_service"),1307:_TT("SYNO.SDS.WebStation.Application","error","err_port_conflict"),1308:_TT("SYNO.SDS.WebStation.Application","error","err_port_conflict"),1309:_TT("SYNO.SDS.WebStation.Application","error","err_port_conflict"),1310:_TT("SYNO.SDS.WebStation.Application","error","err_alias_conflict"),2801:_TT("SYNO.SDS.WebStation.Application","error","err_docker_duplicated_name")};return i[t]&&(e=i[t]),a&&a(t,e),e},Ext.ns("SYNO.SDS.WebStation.Util"),SYNO.SDS.WebStation.Util.PackageInfo=null,SYNO.SDS.WebStation.Util.DestructPackageInfo=function(){delete SYNO.SDS.WebStation.Util.PackageInfo,SYNO.SDS.WebStation.Util.PackageInfo=null},SYNO.SDS.WebStation.Util.CreatePackageInfo=function(){const t={api:"SYNO.WebStation.Status",method:"get",version:1},a={api:"SYNO.WebStation.PHP",method:"get",version:1},e={api:"SYNO.WebStation.Python",method:"get",version:1},i={api:"SYNO.WebStation.ScriptLanguage.Utils",method:"get",version:1,params:{script:{type:"all",property:"default"}}},o={api:"SYNO.Core.Package",method:"list",timeout:3e4,version:2,params:{additional:["status","provide_pkgs"]}},n={api:"SYNO.Core.Package.Server",method:"list",version:2},r={api:"SYNO.Core.Package.Info",method:"get",version:1};SYNO.SDS.WebStation.Util.PackageInfo=new class{constructor(){this.useBetaPackages=!1,this.php=void 0,this.corePackage=void 0,this.corePackageServer=void 0,this.database=void 0,this._dockerImageLatest=void 0,this._packageData=void 0,this.updatingPromise=Promise.resolve(),this.Update(),this._updatingServer=Promise.resolve(),this.UpdatingServer()}async Get(t=!1){return await this.updatingPromise,t&&await this._updatingServer,JSON.parse(JSON.stringify(this._packageData))}async GetPackageNameByIndex(t,a){if(await this.updatingPromise,!["server","php","python"].includes(t))return;let e=this._packageData.backendData[t].find((t=>t.id===a));return void 0!==e?JSON.parse(JSON.stringify(e.name)):null}async GetBackendMap(t,a="all"){if(await this.updatingPromise,["server","php","python","all"].includes(t))return"all"===a?JSON.parse(JSON.stringify(this._packageData.backendData[t])):JSON.parse(JSON.stringify(this._packageData.backendData[t].find((t=>t.id===a))))}async GetStatusByPkgID(t,a=!1){await this.updatingPromise,a&&await this._updatingServer;let e=this._packageData.install;if(!Object.prototype.hasOwnProperty.call(e,t))return"not_installed";switch(e[t].additional.status){case"running":return"enabled";case"stop":return"disabled";case"version_limit":return"error";default:return"-"}}async queryPackages(t,a=!1,e){if(await this.updatingPromise,a&&await this._updatingServer,!["install","official"].includes(t)||"function"!=typeof e)return;let i={};for(let a of Object.values(this._packageData[t]))e(a)&&(i[a.id]=a);return i}async IsSupportDocker(){return await this.updatingPromise,this._packageData.utils.support_docker}async GetPhpData(){return await this.updatingPromise,this._packageData.phpData}async GetPythonData(){return await this.updatingPromise,this._packageData.pythonData}async GetDockerImageLatest(){return await this.updatingPromise,this._dockerImageLatest}async CheckDockerImageLatest(t,a,e){let i=await this.GetDockerImageLatest();if(!i||!i.tags)return!0;let o=i.tags[t];if(void 0===o)return!0;return void 0!==o.find((t=>t.tag===a&&t.hash===e))}async fetchScriptLanguageDefault(){const t=await synowebapi.promises.request(i);return this.scriptLanguage=t}async fetchCorePackageInfo(){const t=await synowebapi.promises.request(r);this.useBetaPackages=!!t.config.blBetaChannel}async fetchWebStationStatusScriptCorePackage(){const i=[a,e,o,t],{has_fail:n,result:r}=await synowebapi.promises.request({compound:{stopwhenerror:!0,params:i}});if(n){const t=r.find((t=>!t.success));throw new Error(`${t.api} fail`)}this.status=r.find((a=>a.api===t.api)).data,this.php=r.find((t=>t.api===a.api)).data,this.python=r.find((t=>t.api===e.api)).data,this.corePackage=r.find((t=>t.api===o.api)).data}compareDockerImageVersion(t,a){let e=t.tag.replace(/[^0-9]+/g," ").split(" ").map((t=>parseInt(t))),i=a.tag.replace(/[^0-9]+/g," ").split(" ").map((t=>parseInt(t)));for(let t=0;t<e.length;t++){if(t>=i.length||e[t]>i[t])return 1;if(e[t]<i[t])return-1}return 0}async fetchDockerImageLatest(){try{this._dockerImageLatest=await synowebapi.promises.request({api:"SYNO.WebStation.Docker",version:1,method:"tags",params:{repo:"all"}}),Object.values(this._dockerImageLatest.tags).forEach((t=>{t.sort(((t,a)=>this.compareDockerImageVersion(a,t)))})),Object.values(this._dockerImageLatest.tags).forEach((t=>{t.forEach((t=>(t.version=t.tag,t.hash&&(t.version=t.version+"@"+t.hash),t)))}))}catch(t){return void SYNO.Debug(t)}}async fetchOnceCorePackageServer(){this.corePackageServer||(this.corePackageServer=await synowebapi.promises.request(n))}Update(){return this.updatingPromise=this._Update(),this.updatingPromise}async _Update(){try{await this.fetchScriptLanguageDefault(),await this.fetchCorePackageInfo(),await this.fetchWebStationStatusScriptCorePackage(),await this.fetchDockerImageLatest()}catch(t){SYNO.Debug.info(t)}this.makePackageData()}UpdatingServer(){return this._updatingServer=this._Update_server(),this._updatingServer}async _Update_server(){try{await this.updatingPromise,await this.fetchOnceCorePackageServer()}catch(t){SYNO.Debug.info(t)}this.makePackageData()}makePackageData(){const t=function(t,a){const e=[s,l,p];if(void 0===t)return e;const i=[...t.packages,...a?t.beta_packages:[]];return[...e,...i].reduce(((t,a)=>({...t,[a.id]:a})),{})}(this.corePackageServer,this.useBetaPackages),a=((e=this.corePackage).packages.forEach((t=>{t.dname=t.name,t.provides=t.additional.provide_pkgs?Object.keys(t.additional.provide_pkgs).find((t=>["PHP","PYTHON"].includes(t))):""})),e.packages.reduce(((t,a)=>({...t,[a.id]:a})),{}));var e;const i=function(t,a){return[{id:0,pkgID:void 0,name:"Nginx"},{id:1,pkgID:"Apache2.2",name:"Apache HTTP Server 2.2"},{id:2,pkgID:"Apache2.4",name:"Apache HTTP Server 2.4"}].filter((e=>"Nginx"===e.name||!!Object.values({...t,...a}).find((t=>t.id===e.pkgID))))}(a,t),{backendDataPhp:o,backendDataPython:n}=function(t={},a,e){function i(t,i="PHP"){return Object.values({...a,...e}).filter((t=>t.provides===i)).map((a=>{let e=null!==t.meta_data?t.meta_data.find((t=>t.name===a.id)):void 0;return{id:void 0===e?null:parseInt(e.id,10),pkgID:a.id,name:a.dname}}))}return{backendDataPhp:i(t.php,"PHP"),backendDataPython:i(t.python,"PYTHON")}}({php:this.php,python:this.python},a,t),r=function(t={},a={}){return{php:t,available_php_backend:a.available_php_backend}}(this.php,this.status),c=function(t={},a={}){return{python:t,available_python_backend:a.available_python_backend}}(this.python,this.status);this._packageData={official:t,install:a,phpData:r,pythonData:c,utils:{support_docker:!!this.status.support_docker},backendData:{server:i,php:o,python:n}}}};const s={provides:"WEBSTATION_SERVICE",auto_upgrade_from:"4.7.4-0136",blupgrade:!1,breakpkgs:null,category:["utilities"],changelog:'<ol style="list-style: decimal; padding-left: 30px;"><li>修正有關 WordPress 的多項安全性弱點( CVE-2018-1000773、 CVE-2018-20147、 CVE-2018-20148、 CVE-2018-20149、 CVE-2018-20150、 CVE-2018-20151、CVE-2018-20152、CVE-2018-20153、CVE-2019-8942、CVE-2019-8943、CVE-2019-9787)。</li><li>升級至 5.2.0 版本。</li></ol>',conflictpkgs:null,deppkgs:{"Apache2.2":{">=":"2.2.31-0005"},MariaDB10:"","PHP5.6":{">=":"5.6.39-0058"},WebStation:{">=":"2.0.0-0065"}},desc:"WordPress 是開放原始碼 (open source) 的部落格發佈平台,採用的技術為 PHP 及 MySQL。此套件可讓您在 Synology NAS 上架設 WordPress 部落格。",distributor:"Synology Inc.",distributor_url:"http://www.synology.com/",dname:"WordPress",download_count:1214293,id:"WordPress",link:"https://global.download.synology.com/download/Package/spk/WordPress/5.2.0-0152/WordPress-5.2.0-0152.spk",maintainer:"WordPress",maintainer_url:"http://tw.wordpress.org/",md5:"17ab8a772a6bb34a0b56e4028bb4e317",package:"WordPress",price:null,qstart:!0,recent_download_count:58796,replaceforcepkgs:null,replacepkgs:null,silent_upgrade:!0,size:9963520,source:"syno",start:!0,thirdparty:!0,thumbnail:["https://global.download.synology.com/download/Package/img/WordPress/5.2.0-0152/thumb_72.png","https://global.download.synology.com/download/Package/img/WordPress/5.2.0-0152/thumb_120.png","https://global.download.synology.com/download/Package/img/WordPress/5.2.0-0152/thumb_256.png"],thumbnail_retina:["https://global.download.synology.com/download/Package/img/WordPress/5.2.0-0152/thumb_256.png","https://global.download.synology.com/download/Package/img/WordPress/5.2.0-0152/thumb_256.png"],type:0,version:"5.2.0-0152"},l={provides:"WEBSTATION_SERVICE",auto_upgrade_from:"1.28.2-0123",blupgrade:!1,breakpkgs:null,category:["utilities"],changelog:'<ol style="list-style: decimal; padding-left: 30px;"><li>升級至 1.30.0 版本以修正多項關於 MediaWiki 的安全性問題 (CVE-2017-8814、CVE-2017-8812、CVE-2017-8815、CVE-2017-8810、CVE-2017-8809、CVE-2017-8808、CVE-2017-8811)。</li></ol>',conflictpkgs:null,deppkgs:{"Apache2.2":{">=":"2.2.31-0005"},MariaDB10:"","PHP5.6":{">=":"5.6.17-0017"},WebStation:{">=":"2.0.0-0065"}},desc:"MediaWiki 是一套極為強大、擴充度高、功能豐富的開放原始碼 wiki 套件,使用 PHP 來處理、呈現資料庫 (如 MySQL) 中儲存的資料。目前廣泛地運用在維基百科與其它 wiki 上。使用者可充分利用其功能與擴充來編輯 wiki 頁面。",distributor:"Synology Inc.",distributor_url:"http://www.synology.com/",dname:"MediaWiki",download_count:326392,id:"MediaWiki",link:"https://global.download.synology.com/download/Package/spk/MediaWiki/1.30.0-0131/MediaWiki-1.30.0-0131.spk",maintainer:"MediaWiki",maintainer_url:"http://www.mediawiki.org/",md5:"bf31a63406d424d344d1eeeac9682164",package:"MediaWiki",price:null,qstart:!0,recent_download_count:3152,replaceforcepkgs:null,replacepkgs:null,silent_install:!0,silent_upgrade:!0,size:31600640,snapshot:["https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/screenshot_01.png"],source:"syno",start:!0,thirdparty:!0,thumbnail:["https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/thumb_72.png","https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/thumb_120.png","https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/thumb_256.png"],thumbnail_retina:["https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/thumb_256.png","https://global.download.synology.com/download/Package/img/MediaWiki/1.30.0-0131/thumb_256.png"],type:0,version:"1.30.0-0131"},p={provides:"WEBSTATION_SERVICE",blupgrade:!1,breakpkgs:null,category:["utilities"],changelog:'<p>問題修正</p><ol style="list-style: decimal; padding-left: 30px;"><li>修正有關 phpMyAdmin 的安全性弱點。</li><li>修正匯入大型檔案時可能會失敗的問題。</li></ol>',conflictpkgs:null,deppkgs:{"PHP5.6":{">=":"5.6.17-0017"},WebStation:{">=":"1.0-0036"}},desc:"phpMyAdmin 是免費的軟體工具,設計用來管理 MySQL 資料庫。只要安裝此套件即可在 DiskStation 上管理 MySQL 資料庫。",distributor:"Synology Inc.",distributor_url:"http://www.synology.com/",dname:"phpMyAdmin",download_count:5739571,id:"phpMyAdmin",link:"https://global.download.synology.com/download/Package/spk/phpMyAdmin/4.8.4-0179/phpMyAdmin-4.8.4-0179.spk",maintainer:"phpMyAdmin devel team",maintainer_url:"http://www.phpmyadmin.net",md5:"cee8c448ab80993d199d7ebd523dd3e0",package:"phpMyAdmin",price:null,qinst:!0,qstart:!0,qupgrade:!0,recent_download_count:240005,replaceforcepkgs:null,replacepkgs:null,silent_install:!0,silent_uninstall:!0,silent_upgrade:!0,size:5785600,snapshot:["https://global.download.synology.com/download/Package/img/phpMyAdmin/4.8.4-0179/screenshot_01.png"],source:"syno",start:!0,thirdparty:!0,thumbnail:["https://global.download.synology.com/download/Package/img/phpMyAdmin/4.8.4-0179/thumb_72.png","https://global.download.synology.com/download/Package/img/phpMyAdmin/4.8.4-0179/thumb_256.png"],thumbnail_retina:["https://global.download.synology.com/download/Package/img/phpMyAdmin/4.8.4-0179/thumb_256.png","https://global.download.synology.com/download/Package/img/phpMyAdmin/4.8.4-0179/thumb_256.png"],type:0,version:"4.8.4-0179"}},SYNO.SDS.WebStation.Util.HomeShareStatus={StatusNormal:0,StatusNotEnable:1,StatusIsEncrypted:2,StatusBackendNotExist:3,StatusUnknownError:4},SYNO.SDS.WebStation.Util.getReqCompoundParam=function(t,a){if(!(a instanceof Array))return null;for(var e=0;e<a.length;e++)if(!1!==SYNO.ux.Utils.checkApiConsistency(t,a[e]))return a[e];return null},SYNO.SDS.WebStation.Util.getSuccessRespCompoundData=function(t,a){if(!(a.result instanceof Array))return null;for(var e=0;e<a.result.length;e++){var i=a.result[e];if(!1!==SYNO.ux.Utils.checkApiConsistency(t,i)){if(!0===i.has_fail||!1===i.success)break;return a.result[e].data?a.result[e].data:null}}return null},SYNO.SDS.WebStation.Util.getFailRespCompoundParam=function(t,a){if(!1===a.has_fail)return null;if(!(a.result instanceof Array))return null;for(var e=0;e<a.result.length;e++){var i=a.result[e];if(t==i.api&&!1===i.success)return i.error}return null},SYNO.SDS.WebStation.Util.genVhostLink=function(t,a,e,i,o){let n="",r=o&&0!==o.length,s=!(i&&0!==i.length)||t&&r,l=s?443:80,p=s?o:i,c=!1,d=-1;for(let t of p)t==l?c=!0:d=t;let g=-1==d||a&&c;return n=s?"https://":"http://",n+=null===e?window.location.hostname:e,!1===g&&(n+=`:${d}`),n},SYNO.SDS.WebStation.Util.genAliasLink=function(t,a){let e="";return e=t?"https://":"http://",e+=window.location.hostname,e+="/"+a,e},SYNO.SDS.WebStation.Util.genPortalLink=function(t={}){let a,e;t.http_port.length>0&&(a="http",e=t.http_port.some((t=>80===t))?80:t.http_port[0]),t.https_port.length>0&&(a="https",e=t.https_port.some((t=>443===t))?443:t.https_port[0]);return`${a}://${t.fqdn||window.location.hostname}:${e}`},SYNO.SDS.WebStation.Util.geti18nString=function(t,a){if(null===t)return a||"";let e=t.split(":");return 3===e.length?_TT(...e):2===e.length?_T(...e):a||t},SYNO.SDS.WebStation.Util.htmlDoubleEncode=function(t){return Ext.util.Format.htmlEncode(Ext.util.Format.htmlEncode(t))};