Support read-only publish service

* 🎨 kernel supports read-only publishing services

* 🐛 Fix authentication vulnerabilities

* 🎨 Protect secret information

* 🎨 Adjust the permission control

* 🎨 Adjust the permission control

* 🎨 Fixed the vulnerability that `getFile` gets file `conf.json`

* 🎨 Add API `/api/setting/setPublish`

* 🎨 Add API `/api/setting/getPublish`

* 🐛 Fixed the issue that PWA-related files could not pass BasicAuth

* 🎨 Add a settings panel for publishing features

* 📝 Add guide for `Publish Service`

* 📝 Update Japanese user guide

* 🎨 Merge fixed static file services
This commit is contained in:
Yingyi / 颖逸 2024-06-12 21:03:51 +08:00 committed by GitHub
parent 536879cb84
commit ba2193403d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 3690 additions and 375 deletions

View file

@ -1,4 +1,17 @@
{
"publish": "Publish",
"publishService": "Publish service",
"publishServiceNotStarted": "Publish Service Not Started",
"publishServiceTip": "When enabled, the publish service will be started. This service publishes the content of the current workspace in read-only mode on the local network.",
"publishServicePort": "Service port",
"publishServicePortTip": "Enable the publish service using the specified port number. If set to <code class='fn__code'>0</code>, a random port will be used.",
"publishServiceAddresses": "Service access addresses",
"publishServiceAddressesTip": "Possible network addresses to access the publish service.",
"publishServiceAuth": "Service basic authentication",
"publishServiceAuthTip": "When enabled, authentication is required to access the publish service.",
"publishServiceAuthAccounts": "Authenticated accounts",
"publishServiceAuthAccountsTip": "List of Basic authentication accounts. Visitors need to enter the username and password from this list to view the published content.",
"publishServiceAuthAccountAdd": "Add account",
"copyMirror": "Copy mirror",
"duplicateMirror": "Duplicate mirror",
"duplicateCompletely": "Duplicate completely",

View file

@ -1,4 +1,17 @@
{
"publish": "Publicar",
"publishService": "Publicar servicio",
"publishServiceNotStarted": "Servicio de publicación no iniciado",
"publishServiceTip": "Al activar esto, se iniciará el servicio de publicación. Este servicio publicará el contenido del espacio de trabajo actual en modo de solo lectura en la LAN",
"publishServicePort": "Número de puerto del servicio",
"publishServicePortTip": "Activar el servicio de publicación con el número de puerto especificado. Si se establece en 0, se utilizará un puerto aleatorio",
"publishServiceAddresses": "Direcciones de acceso al servicio",
"publishServiceAddressesTip": "Direcciones de red desde las que se puede acceder al servicio de publicación",
"publishServiceAuth": "Autenticación básica del servicio",
"publishServiceAuthTip": "Al activar esto, se requerirá autenticación al acceder al servicio de publicación",
"publishServiceAuthAccounts": "Cuentas de autenticación",
"publishServiceAuthAccountsTip": "Lista de cuentas de autenticación básica. Después de activar la autenticación básica, los visitantes deberán ingresar el nombre de usuario y la contraseña de la lista para ver el contenido publicado",
"publishServiceAuthAccountAdd": "Agregar cuenta",
"copyMirror": "Copiar espejo",
"duplicateMirror": "Espejo duplicado",
"duplicateCompletely": "Duplicar completamente",

View file

@ -1,4 +1,17 @@
{
"publish": "Publier",
"publishService": "Publier le service",
"publishServiceNotStarted": "Service de publication non démarré",
"publishServiceTip": "Lorsqu'activé, le service de publication démarre. Ce service publie en mode lecture seule le contenu de l'espace de travail actuel dans le réseau local.",
"publishServicePort": "Numéro de port du service",
"publishServicePortTip": "Active le service de publication avec le numéro de port spécifié. Si défini sur 0, un port aléatoire sera utilisé.",
"publishServiceAddresses": "Adresses d'accès au service",
"publishServiceAddressesTip": "Adresses réseau qui peuvent accéder au service de publication",
"publishServiceAuth": "Authentification Basic du service",
"publishServiceAuthTip": "Lorsqu'activé, une authentification est requise pour accéder au service de publication",
"publishServiceAuthAccounts": "Comptes d'authentification",
"publishServiceAuthAccountsTip": "Liste des comptes d'authentification Basic. Lorsque l'authentification Basic est activée, les visiteurs doivent entrer un nom d'utilisateur et un mot de passe figurant dans cette liste pour consulter le contenu publié.",
"publishServiceAuthAccountAdd": "Ajouter un compte",
"copyMirror": "Copier le miroir",
"duplicateMirror": "Miroir en double",
"duplicateCompletely": "Dupliquer complètement",

View file

@ -1,4 +1,17 @@
{
"publish": "公開する",
"publishService": "サービスを公開する",
"publishServiceNotStarted": "サービスが開始されていません",
"publishServiceTip": "有効にすると、サービスを開始します。このサービスは、現在のワークスペースの内容を読み取り専用モードでローカルネットワークに公開します",
"publishServicePort": "サービスポート",
"publishServicePortTip": "指定したポート番号を使用してサービスを有効にします。0に設定するとランダムなポートが使用されます",
"publishServiceAddresses": "サービスアドレス",
"publishServiceAddressesTip": "サービスを公開することが可能なネットワークアドレス",
"publishServiceAuth": "サービスの基本認証",
"publishServiceAuthTip": "有効にすると、公開サービスへのアクセス時に認証が必要になります",
"publishServiceAuthAccounts": "認証アカウント",
"publishServiceAuthAccountsTip": "基本認証アカウントのリスト。基本認証を有効にした場合、訪問者はリスト内のユーザー名とパスワードを入力して公開内容を表示することができます",
"publishServiceAuthAccountAdd": "アカウントを追加する",
"copyMirror": "ミラーをコピー",
"duplicateMirror": "ミラーを複製",
"duplicateCompletely": "完全に複製",
@ -1523,4 +1536,4 @@
"247": "ファイル [%s] は制限サイズ [%s] を超えているためアップロードされませんでした",
"248": "目標の見出しがコンテナブロック内にあるためドロップできません"
}
}
}

View file

@ -1,4 +1,17 @@
{
"publish": "發布",
"publishService": "發布服務",
"publishServiceNotStarted": "發布服務未啟動",
"publishServiceTip": "啟用後將啟動發布服務。該服務以只讀模式在區域網中發布當前工作空間的內容",
"publishServicePort": "服務端口號",
"publishServicePortTip": "使用指定的端口號啟用發布服務。若設置為 <code class='fn__code'>0</code> 則使用隨機端口",
"publishServiceAddresses": "服務訪問地址",
"publishServiceAddressesTip": "可能訪問到發布服務的網路地址",
"publishServiceAuth": "服務 Basic 認證",
"publishServiceAuthTip": "啟用後在訪問發布服務時需要進行認證",
"publishServiceAuthAccounts": "認證帳戶",
"publishServiceAuthAccountsTip": "Basic 認證帳戶列表。啟用 Basic 認證後訪問者輸入列表中的用戶名與密碼後才能查看發布的內容",
"publishServiceAuthAccountAdd": "添加帳戶",
"copyMirror": "複製鏡像",
"duplicateMirror": "複製為鏡像副本",
"duplicateCompletely": "複製為完整副本",

View file

@ -1,4 +1,17 @@
{
"publish": "发布",
"publishService": "发布服务",
"publishServiceNotStarted": "发布服务未启动",
"publishServiceTip": "启用后将启动发布服务。该服务以只读模式在局域网中发布当前工作空间的内容",
"publishServicePort": "服务端口号",
"publishServicePortTip": "使用指定的端口号启用发布服务。若设置为 <code class='fn__code'>0</code> 则使用随机端口",
"publishServiceAddresses": "服务访问地址",
"publishServiceAddressesTip": "可能访问到发布服务的网络地址",
"publishServiceAuth": "服务 Basic 认证",
"publishServiceAuthTip": "启用后访问者在访问发布服务时需要使用用户名与密码进行认证",
"publishServiceAuthAccounts": "认证账户",
"publishServiceAuthAccountsTip": "Basic 认证账户列表。访问者输入列表中的用户名与密码后才能查看发布的内容",
"publishServiceAuthAccountAdd": "添加账户",
"copyMirror": "复制镜像",
"duplicateMirror": "复制为镜像副本",
"duplicateCompletely": "复制为完整副本",

View file

@ -1,2 +0,0 @@
.idea/
.siyuan/history/

View file

@ -1 +1 @@
{"20200923234011-ieuun1p":1,"20200923234602-gy54e67":8,"20200923234731-h3zkwm2":3,"20200924093441-ft2rhps":1,"20200924095938-a9p5450":2,"20200924100110-vcg96wy":1,"20200924100635-ms0p9lb":6,"20200924100717-yzwzn64":21,"20200924100744-br924ar":10,"20200924100808-j9sddk9":2,"20200924100906-0u4zfq3":4,"20200924100950-9op5xi1":18,"20200924101106-19z4kaa":1,"20200924101200-gss5vee":4,"20200924101225-k254i8g":2,"20200924101256-f8b1sbi":3,"20201004194026-s8h2cog":19,"20201117112518-dott91x":6,"20201121224345-rc27qvo":9,"20201204184532-3qm9l8n":11,"20201210233038-3xr19g5":5,"20201222100222-q47d64s":3,"20201222100339-i5hzcph":2,"20201227201128-m1wrouw":20,"20201227201751-gv0fpx2":22,"20210110181011-fbhoesf":5,"20210117215840-jcl17fx":4,"20210127203829-qe2mzof":12,"20210331201142-4g923es":14,"20210505164949-c085p1d":3,"20210613191509-cbkxcbz":7,"20210615213222-vs5tzbd":15,"20210721112159-9p645xm":1,"20210721112206-mhr9wxi":2,"20210721160238-yvhbh0h":4,"20210808180303-6yi0dv5":1,"20210808180303-axh6q1d":4,"20210808180303-h361q1i":2,"20210808180303-l3qg72k":3,"20210808180303-xaduj2o":5,"20210824202056-udkf7wg":8,"20211010212318-3wx2kqb":13,"20220105101227-n5zpr1a":6,"20220415232231-pqcizol":1,"20220628204454-hhxohv5":2,"20220708103401-mgydrfg":3,"20221016204105-qx2aq0g":3,"20221223221636-ms2b4w9":16,"20230104152135-1iei0xa":23,"20230106104821-9nfphwm":1,"20230304000547-ibldj1z":17,"20230405172236-pg3l9eu":6,"20230429115711-ejbts4s":5,"20230506205948-yah52eb":9,"20230802114825-2jkkct7":5,"20230805231614-vqn28eh":7,"20230805231816-h1z9mpc":2,"20230805232018-hgrq0ju":1,"20230805232134-3d6mx2k":2,"20240113110040-7sgw8kl":2,"20240119211017-1vbbt95":4,"20240119212048-0huuevw":5,"20240208172514-9dsv6na":7,"20240317202444-5txwumu":7}
{"20200923234011-ieuun1p":1,"20200923234602-gy54e67":8,"20200923234731-h3zkwm2":3,"20200924093441-ft2rhps":1,"20200924095938-a9p5450":2,"20200924100110-vcg96wy":1,"20200924100635-ms0p9lb":6,"20200924100717-yzwzn64":21,"20200924100744-br924ar":10,"20200924100808-j9sddk9":2,"20200924100906-0u4zfq3":4,"20200924100950-9op5xi1":18,"20200924101106-19z4kaa":1,"20200924101200-gss5vee":4,"20200924101225-k254i8g":2,"20200924101256-f8b1sbi":3,"20201004194026-s8h2cog":19,"20201117112518-dott91x":6,"20201121224345-rc27qvo":9,"20201204184532-3qm9l8n":11,"20201210233038-3xr19g5":5,"20201222100222-q47d64s":3,"20201222100339-i5hzcph":2,"20201227201128-m1wrouw":20,"20201227201751-gv0fpx2":22,"20210110181011-fbhoesf":5,"20210117215840-jcl17fx":4,"20210127203829-qe2mzof":12,"20210331201142-4g923es":14,"20210505164949-c085p1d":3,"20210613191509-cbkxcbz":7,"20210615213222-vs5tzbd":15,"20210721112159-9p645xm":1,"20210721112206-mhr9wxi":2,"20210721160238-yvhbh0h":4,"20210808180303-6yi0dv5":1,"20210808180303-axh6q1d":4,"20210808180303-h361q1i":2,"20210808180303-l3qg72k":3,"20210808180303-xaduj2o":5,"20210824202056-udkf7wg":8,"20211010212318-3wx2kqb":13,"20220105101227-n5zpr1a":6,"20220415232231-pqcizol":1,"20220628204454-hhxohv5":2,"20220708103401-mgydrfg":3,"20221016204105-qx2aq0g":3,"20221223221636-ms2b4w9":16,"20230104152135-1iei0xa":23,"20230106104821-9nfphwm":1,"20230304000547-ibldj1z":17,"20230405172236-pg3l9eu":6,"20230429115711-ejbts4s":5,"20230506205948-yah52eb":9,"20230802114825-2jkkct7":5,"20230805231614-vqn28eh":7,"20230805231816-h1z9mpc":2,"20230805232018-hgrq0ju":1,"20230805232134-3d6mx2k":2,"20240113110040-7sgw8kl":2,"20240119211017-1vbbt95":4,"20240119212048-0huuevw":5,"20240208172514-9dsv6na":7,"20240317202444-5txwumu":7,"20240517031132-jmr5ihm":24}

View file

@ -0,0 +1,526 @@
{
"ID": "20240517031132-jmr5ihm",
"Spec": "1",
"Type": "NodeDocument",
"Properties": {
"id": "20240517031132-jmr5ihm",
"title": "Publish service",
"type": "doc",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-um049u9",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031304-um049u9",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Overview"
}
]
},
{
"ID": "20240517031304-kebcgzv",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-kebcgzv",
"updated": "20240517031305"
},
"Children": [
{
"Type": "NodeText",
"Data": "Joplin supports publishing the content of the current workspace in read-only mode on the local area network."
}
]
},
{
"ID": "20240517031304-7e0kvj3",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031304-7e0kvj3",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Usage"
}
]
},
{
"ID": "20240517031304-gt5qj60",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-gt5qj60",
"updated": "20240517031305"
},
"Children": [
{
"ID": "20240517031304-sjppgk3",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-sjppgk3",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-r9a0anm",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-r9a0anm",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Open "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Settings"
},
{
"Type": "NodeText",
"Data": " - "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Publish"
},
{
"Type": "NodeText",
"Data": " to enter the publishing service settings panel."
}
]
}
]
},
{
"ID": "20240517031304-u6inl9h",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-u6inl9h",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-ye7ittw",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-ye7ittw",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Set the "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Server port"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031304-olvdqhj",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-olvdqhj",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-1ttdtl4",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-1ttdtl4",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-sl59b81",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-sl59b81",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "The default port number is "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "6808"
},
{
"Type": "NodeText",
"Data": "."
}
]
}
]
},
{
"ID": "20240517031304-t37dfgj",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-t37dfgj",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-mxx5df4",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-mxx5df4",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "If the port number is set to "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "0"
},
{
"Type": "NodeText",
"Data": ", a random port will be used."
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031304-y4kcmaf",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-y4kcmaf",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-5qilsih",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-5qilsih",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "If access control is required for the publishing service:"
}
]
},
{
"ID": "20240517031304-659m8fi",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-659m8fi",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-xh0kq2y",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-xh0kq2y",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-lay209u",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-lay209u",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Add "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Authenticated accounts"
},
{
"Type": "NodeText",
"Data": " and enable the "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Service basic authentication"
},
{
"Type": "NodeText",
"Data": " switch."
}
]
}
]
},
{
"ID": "20240517031304-ri1nm5j",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-ri1nm5j",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-4y267ml",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-4y267ml",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "When enabled, the publishing service will use the "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme",
"TextMarkTextContent": "Basic authentication scheme"
},
{
"Type": "NodeText",
"Data": " to authenticate visitors."
}
]
},
{
"ID": "20240517031304-h61xxm7",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-h61xxm7",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-1k96w0z",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-1k96w0z",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-l5hafpz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-l5hafpz",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Visitors must enter the username and password set in the \"Authentication Accounts\" before browsing the published content."
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031304-0nps2p8",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-0nps2p8",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-y16fc8r",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-y16fc8r",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Enable the "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Publish service"
},
{
"Type": "NodeText",
"Data": " switch."
}
]
}
]
}
]
},
{
"ID": "20240517031304-6cy4lbq",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031304-6cy4lbq",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "Note"
}
]
},
{
"ID": "20240517031304-3slh48m",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-3slh48m",
"updated": "20240517031305"
},
"Children": [
{
"ID": "20240517031304-uquw6i6",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-uquw6i6",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-j38u7hu",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-j38u7hu",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "After enabling the publishing service, visitors can browse the content of the entire workspace."
}
]
}
]
},
{
"ID": "20240517031304-c6iqquc",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031304-c6iqquc",
"updated": "20240517031304"
},
"Children": [
{
"ID": "20240517031304-1qsa7qz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031304-1qsa7qz",
"updated": "20240517031304"
},
"Children": [
{
"Type": "NodeText",
"Data": "When "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Service basic authentication"
},
{
"Type": "NodeText",
"Data": " is disabled, all visitors can browse the content of the entire workspace without authentication."
}
]
}
]
}
]
}
]
}

View file

@ -1,2 +0,0 @@
.idea/
.siyuan/history/

View file

@ -1 +1 @@
{"20200812220555-lj3enxa":1,"20200813004551-gm0pbn1":18,"20200813004931-q4cu8na":1,"20200813013559-sgbzl5k":3,"20200813093015-u6bopdt":3,"20200813125307-pxsjela":2,"20200813131152-0wk5akh":4,"20200813163359-v04n73b":10,"20200822191536-rm6hwid":4,"20200825162036-4dx365o":1,"20200828105441-r76vmu5":21,"20200905090211-2vixtlf":2,"20200910201551-h4twhas":6,"20200915214115-42b8zma":10,"20200922102318-oz84yu3":2,"20201004184819-nj8ibyg":19,"20201117101902-2ewjjum":6,"20201121212605-9td1a62":11,"20201204181006-7bkppue":11,"20201210103036-1x3vm8t":5,"20201222093044-rx4zjoy":2,"20201222095049-hghafhe":3,"20201227173504-847cs1q":20,"20201227194925-7ipoiv6":22,"20210110175347-2xrwoiq":5,"20210117211155-56n4odu":4,"20210127202655-2334vvv":12,"20210331200042-94gs1hh":14,"20210505163537-oo97zov":3,"20210612224500-ywcms1m":7,"20210615211733-v6rzowm":15,"20210808180320-abz7w6k":2,"20210808180320-fqgskfj":1,"20210808180320-gyngv2x":3,"20210808180320-qgr0b3q":5,"20210808180321-hbvl5c2":6,"20210824201257-cy7icrc":8,"20211010211311-ffz0wbu":13,"20220415190432-r3xqn3r":1,"20220628204444-9n0y9h2":2,"20221016213308-uz5af79":3,"20221223215557-o6gfsoy":16,"20230104144904-39br4c6":23,"20230106101434-e6g4av3":1,"20230303235619-ex5l63e":17,"20230405155631-leo4vc6":6,"20230428153709-hioyy5l":7,"20230429114837-70asb4j":5,"20230506210010-houyyvy":9,"20230519105228-hm0y74i":8,"20230805222417-2lj3dvk":7,"20230805225107-qm1m2f5":2,"20230805230131-sn7obzb":1,"20230805230218-aea8icj":2,"20230808120347-3cob0nb":2,"20230808120347-mw3qrwy":4,"20230808120347-pzvmkik":1,"20230808120348-hynr7og":5,"20230808120348-lgcp9zm":3,"20230808120348-vaxi6eq":6,"20230808120348-yut741f":7,"20240113102857-c63dmo5":2,"20240119205452-o8xp4ve":4,"20240119205543-hknwwrl":5,"20240208113259-nykkvaq":7,"20240317200013-fim8wm8":9}
{"20200812220555-lj3enxa":1,"20200813004551-gm0pbn1":18,"20200813004931-q4cu8na":1,"20200813013559-sgbzl5k":3,"20200813093015-u6bopdt":3,"20200813125307-pxsjela":2,"20200813131152-0wk5akh":4,"20200813163359-v04n73b":10,"20200822191536-rm6hwid":4,"20200825162036-4dx365o":1,"20200828105441-r76vmu5":21,"20200905090211-2vixtlf":2,"20200910201551-h4twhas":6,"20200915214115-42b8zma":10,"20200922102318-oz84yu3":2,"20201004184819-nj8ibyg":19,"20201117101902-2ewjjum":6,"20201121212605-9td1a62":11,"20201204181006-7bkppue":11,"20201210103036-1x3vm8t":5,"20201222093044-rx4zjoy":2,"20201222095049-hghafhe":3,"20201227173504-847cs1q":20,"20201227194925-7ipoiv6":22,"20210110175347-2xrwoiq":5,"20210117211155-56n4odu":4,"20210127202655-2334vvv":12,"20210331200042-94gs1hh":14,"20210505163537-oo97zov":3,"20210612224500-ywcms1m":7,"20210615211733-v6rzowm":15,"20210808180320-abz7w6k":2,"20210808180320-fqgskfj":1,"20210808180320-gyngv2x":3,"20210808180320-qgr0b3q":5,"20210808180321-hbvl5c2":6,"20210824201257-cy7icrc":8,"20211010211311-ffz0wbu":13,"20220415190432-r3xqn3r":1,"20220628204444-9n0y9h2":2,"20221016213308-uz5af79":3,"20221223215557-o6gfsoy":16,"20230104144904-39br4c6":23,"20230106101434-e6g4av3":1,"20230303235619-ex5l63e":17,"20230405155631-leo4vc6":6,"20230428153709-hioyy5l":7,"20230429114837-70asb4j":5,"20230506210010-houyyvy":9,"20230519105228-hm0y74i":8,"20230805222417-2lj3dvk":7,"20230805225107-qm1m2f5":2,"20230805230131-sn7obzb":1,"20230805230218-aea8icj":2,"20230808120347-3cob0nb":2,"20230808120347-mw3qrwy":4,"20230808120347-pzvmkik":1,"20230808120348-hynr7og":5,"20230808120348-lgcp9zm":3,"20230808120348-vaxi6eq":6,"20230808120348-yut741f":7,"20240113102857-c63dmo5":2,"20240119205452-o8xp4ve":4,"20240119205543-hknwwrl":5,"20240208113259-nykkvaq":7,"20240317200013-fim8wm8":9,"20240517031028-xqinazo":24}

View file

@ -0,0 +1,540 @@
{
"ID": "20240517031028-xqinazo",
"Spec": "1",
"Type": "NodeDocument",
"Properties": {
"id": "20240517031028-xqinazo",
"title": "发布服务",
"type": "doc",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-7ox0m9z",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031044-7ox0m9z",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "概述"
}
]
},
{
"ID": "20240517031044-6mppc0k",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-6mppc0k",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "思源笔记支持以只读模式在局域网中发布当前工作空间的内容。"
}
]
},
{
"ID": "20240517031044-anhkwow",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031044-anhkwow",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用方式"
}
]
},
{
"ID": "20240517031044-0vj6or7",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031044-0vj6or7",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-8ugboo7",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-8ugboo7",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-grogeue",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-grogeue",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "打开 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "设置"
},
{
"Type": "NodeText",
"Data": " - "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "发布"
},
{
"Type": "NodeText",
"Data": " 进入发布服务的设置面板"
}
]
}
]
},
{
"ID": "20240517031044-mta08zv",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-mta08zv",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-7dg9xy9",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-7dg9xy9",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "设置 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服务端口号"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031044-vzj8o1a",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031044-vzj8o1a",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-t2igim6",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-t2igim6",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-8ghv9tj",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-8ghv9tj",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "默认的端口号为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "6808"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
]
},
{
"ID": "20240517031044-3oto1iz",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-3oto1iz",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-0m68jzx",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-0m68jzx",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "若端口号设置为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "0"
},
{
"Type": "NodeText",
"Data": " 将使用随机端口"
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031044-ddii8sb",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-ddii8sb",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-vaiskyz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-vaiskyz",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "若需要对发布服务进行访问控制"
}
]
},
{
"ID": "20240517031044-ze7l6sg",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031044-ze7l6sg",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-fxpcxvc",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-fxpcxvc",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-bno9bca",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-bno9bca",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "添加 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "认证账户"
},
{
"Type": "NodeText",
"Data": " 并开启 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服务 Basic 认证"
},
{
"Type": "NodeText",
"Data": " 开关"
}
]
}
]
},
{
"ID": "20240517031044-29kw4ks",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-29kw4ks",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-g05n8gc",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-g05n8gc",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "开启后发布服务将使用 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication#basic_验证方案",
"TextMarkTextContent": "Basic 验证方案"
},
{
"Type": "NodeText",
"Data": " 对访问者进行认证"
}
]
},
{
"ID": "20240517031044-e54f9vf",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031044-e54f9vf",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-kr1t232",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-kr1t232",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-rf8nyba",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-rf8nyba",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "访问者在浏览发布内容前必须正确输入 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "认证账户"
},
{
"Type": "NodeText",
"Data": " 中设置的用户名与密码"
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031044-s5d5aak",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-s5d5aak",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-ec9vaac",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-ec9vaac",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "开启 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "发布服务"
},
{
"Type": "NodeText",
"Data": " 开关"
}
]
}
]
}
]
},
{
"ID": "20240517031044-6le4t1r",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031044-6le4t1r",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeTextMark",
"TextMarkType": "tag",
"TextMarkTextContent": "注意"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031044-ahzjzvg",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031044-ahzjzvg",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-8f3g2fd",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-8f3g2fd",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-uiys91u",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-uiys91u",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "开启发布服务后访问者可以浏览整个工作空间的内容"
}
]
}
]
},
{
"ID": "20240517031044-979coq3",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031044-979coq3",
"updated": "20240517031044"
},
"Children": [
{
"ID": "20240517031044-7be46qj",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031044-7be46qj",
"updated": "20240517031044"
},
"Children": [
{
"Type": "NodeText",
"Data": "关闭 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服务 Basic 认证"
},
{
"Type": "NodeText",
"Data": " 后所有的访问者无需认证即可浏览整个工作空间的内容"
}
]
}
]
}
]
}
]
}

View file

@ -1,2 +0,0 @@
.idea/
.siyuan/history/

View file

@ -1 +1 @@
{"20211226114339-dk0gtpr":8,"20211226114929-08ap1r0":9,"20211226115043-afhev0g":4,"20211226115227-r1rty9v":3,"20211226115423-d5z1joq":1,"20211226115825-mhcslw2":1,"20211226120055-9mityht":1,"20211226120147-ib6yy3i":2,"20211226120247-63nd8y5":3,"20211226120349-rbkmozu":4,"20211226120422-bkzsd2e":5,"20211226120508-yzh70eh":6,"20211226120802-77aj0is":7,"20211226120854-dr1jfx2":2,"20211226120933-vnjgwwh":3,"20211226121109-f060fkg":4,"20211226121203-rjjngpz":5,"20211226121319-emrk2yy":1,"20211226121322-9argcys":3,"20211226121329-c5v3dto":22,"20211226121332-irgblss":4,"20211226121438-xaafdo8":2,"20211226121503-k3jma6m":1,"20211226121808-fnxmngk":2,"20211226122358-hctqcn5":21,"20211226122459-08mi5cq":20,"20211226122523-rl8356a":19,"20211226122549-jktxego":18,"20211226122707-8cr09co":15,"20211226122728-cnqf7rz":14,"20211226122814-r1rdpcx":13,"20211226122943-st7fpcj":12,"20211226123004-dplpw0o":11,"20211226123038-4umgpxy":10,"20211226123101-qjw03ab":8,"20211226123130-jpeg5b2":6,"20211226123154-fd5e001":5,"20211226123216-tlxw66f":4,"20211226123241-51pujtr":3,"20211226123302-akitvb1":2,"20220105101348-corstqc":6,"20220415232129-shpzg6r":1,"20220628204420-ui79vkt":2,"20220708102441-u6wopo9":3,"20221016213639-1nag9jj":3,"20221223221501-mops33i":16,"20230104151953-48hwkwf":23,"20230106104645-o838uew":1,"20230304000829-9jwu3po":17,"20230405172131-yb16aax":6,"20230429115206-ob8nl8t":5,"20230506211210-1roopyo":9,"20230805232636-zh0adz2":6,"20230805232719-04mqbcx":2,"20230805232903-erdoerp":1,"20230805232920-5fdco36":2,"20240113110500-dz2ae4n":2,"20240119210914-a2tm8c4":4,"20240119212000-qkldbjm":5,"20240208171522-y7dxcno":7,"20240317202230-l8duv3r":7,"20240508010647-8nuyk31":5}
{"20211226114339-dk0gtpr":8,"20211226114929-08ap1r0":9,"20211226115043-afhev0g":4,"20211226115227-r1rty9v":3,"20211226115423-d5z1joq":1,"20211226115825-mhcslw2":1,"20211226120055-9mityht":1,"20211226120147-ib6yy3i":2,"20211226120247-63nd8y5":3,"20211226120349-rbkmozu":4,"20211226120422-bkzsd2e":5,"20211226120508-yzh70eh":6,"20211226120802-77aj0is":7,"20211226120854-dr1jfx2":2,"20211226120933-vnjgwwh":3,"20211226121109-f060fkg":4,"20211226121203-rjjngpz":5,"20211226121319-emrk2yy":1,"20211226121322-9argcys":3,"20211226121329-c5v3dto":22,"20211226121332-irgblss":4,"20211226121438-xaafdo8":2,"20211226121503-k3jma6m":1,"20211226121808-fnxmngk":2,"20211226122358-hctqcn5":21,"20211226122459-08mi5cq":20,"20211226122523-rl8356a":19,"20211226122549-jktxego":18,"20211226122707-8cr09co":15,"20211226122728-cnqf7rz":14,"20211226122814-r1rdpcx":13,"20211226122943-st7fpcj":12,"20211226123004-dplpw0o":11,"20211226123038-4umgpxy":10,"20211226123101-qjw03ab":8,"20211226123130-jpeg5b2":6,"20211226123154-fd5e001":5,"20211226123216-tlxw66f":4,"20211226123241-51pujtr":3,"20211226123302-akitvb1":2,"20220105101348-corstqc":6,"20220415232129-shpzg6r":1,"20220628204420-ui79vkt":2,"20220708102441-u6wopo9":3,"20221016213639-1nag9jj":3,"20221223221501-mops33i":16,"20230104151953-48hwkwf":23,"20230106104645-o838uew":1,"20230304000829-9jwu3po":17,"20230405172131-yb16aax":6,"20230429115206-ob8nl8t":5,"20230506211210-1roopyo":9,"20230805232636-zh0adz2":6,"20230805232719-04mqbcx":2,"20230805232903-erdoerp":1,"20230805232920-5fdco36":2,"20240113110500-dz2ae4n":2,"20240119210914-a2tm8c4":4,"20240119212000-qkldbjm":5,"20240208171522-y7dxcno":7,"20240317202230-l8duv3r":7,"20240508010647-8nuyk31":5,"20240517031052-mgoxs16":24}

View file

@ -0,0 +1,540 @@
{
"ID": "20240517031052-mgoxs16",
"Spec": "1",
"Type": "NodeDocument",
"Properties": {
"id": "20240517031052-mgoxs16",
"title": "發布服務",
"type": "doc",
"updated": "20240517031115"
},
"Children": [
{
"ID": "20240517031115-pjkrctx",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031115-pjkrctx",
"updated": "20240517031115"
},
"Children": [
{
"Type": "NodeText",
"Data": "概述"
}
]
},
{
"ID": "20240517031116-a0xf075",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-a0xf075",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "思源筆記支援以只讀模式在區域網路中發佈當前工作空間的內容。"
}
]
},
{
"ID": "20240517031116-ml8jd6n",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031116-ml8jd6n",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用方式"
}
]
},
{
"ID": "20240517031116-5u42tlr",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031116-5u42tlr",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-06mevu7",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-06mevu7",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-wqo2aje",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-wqo2aje",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "開啟 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "設定"
},
{
"Type": "NodeText",
"Data": " - "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "發佈"
},
{
"Type": "NodeText",
"Data": " 進入發佈服務的設定面板"
}
]
}
]
},
{
"ID": "20240517031116-dsvhebl",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-dsvhebl",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-13481er",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-13481er",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "設定 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服務端口號"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031116-sjbg5cn",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031116-sjbg5cn",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-z1q43ui",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-z1q43ui",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-ssdjmbf",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-ssdjmbf",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "默認的端口號為 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "6808"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
]
},
{
"ID": "20240517031116-jkcxgaj",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-jkcxgaj",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-ka1wome",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-ka1wome",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "若端口號設定為 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "0"
},
{
"Type": "NodeText",
"Data": " 將使用隨機端口"
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031116-ipkirs4",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-ipkirs4",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-g8qr29s",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-g8qr29s",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "若需要對發佈服務進行訪問控制"
}
]
},
{
"ID": "20240517031116-maj6mmd",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031116-maj6mmd",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-du7rttx",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-du7rttx",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-ct3chrz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-ct3chrz",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "添加 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "認證帳戶"
},
{
"Type": "NodeText",
"Data": " 並開啟 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服務 Basic 認證"
},
{
"Type": "NodeText",
"Data": " 開關"
}
]
}
]
},
{
"ID": "20240517031116-dlaep2b",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-dlaep2b",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-3u2v8g7",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-3u2v8g7",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "開啟後發佈服務將使用 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "a",
"TextMarkAHref": "https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication#basic_验证方案",
"TextMarkTextContent": "Basic 驗證方案"
},
{
"Type": "NodeText",
"Data": " 對訪問者進行認證"
}
]
},
{
"ID": "20240517031116-qmzfje7",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031116-qmzfje7",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-xthto7w",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-xthto7w",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-kbz5qye",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-kbz5qye",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "訪問者在瀏覽發佈內容前必須正確輸入 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "認證帳戶"
},
{
"Type": "NodeText",
"Data": " 中設定的用戶名與密碼"
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"ID": "20240517031116-bx01v3n",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-bx01v3n",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-44j60lx",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-44j60lx",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "開啟 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "發佈服務"
},
{
"Type": "NodeText",
"Data": " 開關"
}
]
}
]
}
]
},
{
"ID": "20240517031116-2v0lh0m",
"Type": "NodeHeading",
"HeadingLevel": 3,
"Properties": {
"id": "20240517031116-2v0lh0m",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeTextMark",
"TextMarkType": "tag",
"TextMarkTextContent": "注意"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031116-lx0pe26",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031116-lx0pe26",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-kvje8ru",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-kvje8ru",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-gydcx3b",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-gydcx3b",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "開啟發佈服務後訪問者可以瀏覽整個工作空間的內容"
}
]
}
]
},
{
"ID": "20240517031116-ufsul2c",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20240517031116-ufsul2c",
"updated": "20240517031116"
},
"Children": [
{
"ID": "20240517031116-xyb4012",
"Type": "NodeParagraph",
"Properties": {
"id": "20240517031116-xyb4012",
"updated": "20240517031116"
},
"Children": [
{
"Type": "NodeText",
"Data": "關閉 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "服務 Basic 認證"
},
{
"Type": "NodeText",
"Data": " 後所有的訪問者無需認證即可瀏覽整個工作空間的內容"
}
]
}
]
}
]
}
]
}

View file

@ -1 +1 @@
{"20240530101000-0zd9si2":13,"20240530101000-1m5un7l":10,"20240530101000-1vvnhju":6,"20240530101000-35bbvcx":2,"20240530101000-3eaevtp":7,"20240530101000-3ourzoa":2,"20240530101000-3qhz7br":1,"20240530101000-3xv6jjr":9,"20240530101000-40hohog":19,"20240530101000-4cqkoel":23,"20240530101000-4p096e8":1,"20240530101000-4qitucx":1,"20240530101000-58z6rjh":2,"20240530101000-5gi76ax":8,"20240530101000-5k5d5i3":2,"20240530101000-6x9ivi7":11,"20240530101000-75auqcn":6,"20240530101000-78d5w10":4,"20240530101000-7yv4y5z":4,"20240530101000-875snki":7,"20240530101000-8m2dowc":9,"20240530101000-96n5y9v":1,"20240530101000-a91lmk2":3,"20240530101000-bb0qktp":1,"20240530101000-bgv304g":8,"20240530101000-boiita2":4,"20240530101000-bpj42r0":2,"20240530101000-cb37szr":7,"20240530101000-d31i9v5":2,"20240530101000-dro2zi9":5,"20240530101000-dytmky4":22,"20240530101000-e6z5okf":3,"20240530101000-ei5t6tt":17,"20240530101000-f16hpct":20,"20240530101000-flot1gj":7,"20240530101000-g3ugxml":5,"20240530101000-gc0tuyd":3,"20240530101000-gcdp3gl":3,"20240530101000-gvtksyj":1,"20240530101000-h0cp5vx":5,"20240530101000-hkgs92c":5,"20240530101000-hnu6o79":2,"20240530101000-hq9sn3k":1,"20240530101000-jp793ic":4,"20240530101000-mpln2lp":6,"20240530101000-mrlr6e9":4,"20240530101000-na9sys7":1,"20240530101000-odye3ea":3,"20240530101000-qf0xtkd":2,"20240530101000-scr2p21":5,"20240530101000-to5uvpi":12,"20240530101000-txrc7z1":15,"20240530101000-uxno1yp":3,"20240530101000-vejnh1k":1,"20240530101000-vql5s27":5,"20240530101000-wo49zvq":2,"20240530101000-xc13cm6":6,"20240530101000-xq26o73":21,"20240530101000-xr22qn8":4,"20240530101000-xsbxokr":18,"20240530101000-ynpmvl7":16,"20240530101000-zj4k048":3,"20240530101000-znj103k":10,"20240530101000-zprnpfi":14}
{"20240530101000-0zd9si2":13,"20240530101000-1m5un7l":10,"20240530101000-1vvnhju":6,"20240530101000-35bbvcx":2,"20240530101000-3eaevtp":7,"20240530101000-3ourzoa":2,"20240530101000-3qhz7br":1,"20240530101000-3xv6jjr":9,"20240530101000-40hohog":19,"20240530101000-4cqkoel":23,"20240530101000-4p096e8":1,"20240530101000-4qitucx":1,"20240530101000-58z6rjh":2,"20240530101000-5gi76ax":8,"20240530101000-5k5d5i3":2,"20240530101000-6x9ivi7":11,"20240530101000-75auqcn":6,"20240530101000-78d5w10":4,"20240530101000-7yv4y5z":4,"20240530101000-875snki":7,"20240530101000-8m2dowc":9,"20240530101000-96n5y9v":1,"20240530101000-a91lmk2":3,"20240530101000-bb0qktp":1,"20240530101000-bgv304g":8,"20240530101000-boiita2":4,"20240530101000-bpj42r0":2,"20240530101000-cb37szr":7,"20240530101000-d31i9v5":2,"20240530101000-dro2zi9":5,"20240530101000-dytmky4":22,"20240530101000-e6z5okf":3,"20240530101000-ei5t6tt":17,"20240530101000-f16hpct":20,"20240530101000-flot1gj":7,"20240530101000-g3ugxml":5,"20240530101000-gc0tuyd":3,"20240530101000-gcdp3gl":3,"20240530101000-gvtksyj":1,"20240530101000-h0cp5vx":5,"20240530101000-hkgs92c":5,"20240530101000-hnu6o79":2,"20240530101000-hq9sn3k":1,"20240530101000-jp793ic":4,"20240530101000-mpln2lp":6,"20240530101000-mrlr6e9":4,"20240530101000-na9sys7":1,"20240530101000-odye3ea":3,"20240530101000-qf0xtkd":2,"20240530101000-scr2p21":5,"20240530101000-to5uvpi":12,"20240530101000-txrc7z1":15,"20240530101000-uxno1yp":3,"20240530101000-vejnh1k":1,"20240530101000-vql5s27":5,"20240530101000-wo49zvq":2,"20240530101000-xc13cm6":6,"20240530101000-xq26o73":21,"20240530101000-xr22qn8":4,"20240530101000-xsbxokr":18,"20240530101000-ynpmvl7":16,"20240530101000-zj4k048":3,"20240530101000-znj103k":10,"20240530101000-zprnpfi":14,"20240610233601-ylh1mvk":24}

View file

@ -0,0 +1,676 @@
{
"ID": "20240610233601-ylh1mvk",
"Spec": "1",
"Type": "NodeDocument",
"Properties": {
"id": "20240610233601-ylh1mvk",
"title": "サービスの公開",
"type": "doc",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-jjii9tu",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240610233629-jjii9tu",
"updated": "20240610235250"
},
"Children": [
{
"Type": "NodeHeadingC8hMarker",
"Data": "## ",
"Properties": {
"id": ""
}
},
{
"Type": "NodeText",
"Data": "概要",
"Properties": {
"id": ""
}
}
]
},
{
"ID": "20240610233629-49em84g",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-49em84g",
"updated": "20240610233739"
},
"Children": [
{
"Type": "NodeText",
"Data": "SiYuan Note は、現在のワークスペースの内容を読み取り専用モードでローカルネットワークで公開することができます。",
"Properties": {
"id": ""
}
}
]
},
{
"ID": "20240610233629-bxuf2mx",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240610233629-bxuf2mx",
"updated": "20240610235250"
},
"Children": [
{
"Type": "NodeText",
"Data": "使い方"
}
]
},
{
"ID": "20240610233629-7d7e66r",
"Type": "NodeList",
"ListData": {
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-7d7e66r",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-jn7c5xq",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-jn7c5xq",
"updated": "20240610234354"
},
"Children": [
{
"ID": "20240610233629-ibn4bp6",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-ibn4bp6",
"updated": "20240610234354"
},
"Children": [
{
"Type": "NodeText",
"Data": ""
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "設定"
},
{
"Type": "NodeText",
"Data": " - "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "公開する"
},
{
"Type": "NodeText",
"Data": " に移動して、公開サービスの設定パネルに入ります。"
}
]
}
]
},
{
"ID": "20240610233629-j8ml6bw",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-j8ml6bw",
"updated": "20240610234344"
},
"Children": [
{
"ID": "20240610233629-fubq5bz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-fubq5bz",
"updated": "20240610234344"
},
"Children": [
{
"Type": "NodeText",
"Data": ""
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "サービスポート"
},
{
"Type": "NodeText",
"Data": " を設定します。"
}
]
},
{
"ID": "20240610233629-d9q97le",
"Type": "NodeList",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-d9q97le",
"updated": "20240610233629"
},
"Children": [
{
"ID": "20240610233629-y8ynj1h",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-y8ynj1h",
"updated": "20240610233629"
},
"Children": [
{
"ID": "20240610233629-fwe6fgu",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-fwe6fgu",
"updated": "20240610233629"
},
"Children": [
{
"Type": "NodeText",
"Data": "デフォルトのポート番号は ",
"Properties": {
"id": ""
}
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "6808"
},
{
"Type": "NodeText",
"Data": " です。",
"Properties": {
"id": ""
}
}
]
}
]
},
{
"ID": "20240610233629-amkxqp8",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-amkxqp8",
"updated": "20240610233629"
},
"Children": [
{
"ID": "20240610233629-726ai0u",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-726ai0u",
"updated": "20240610233629"
},
"Children": [
{
"Type": "NodeText",
"Data": "ポート番号を ",
"Properties": {
"id": ""
}
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "0"
},
{
"Type": "NodeText",
"Data": " に設定すると、ランダムなポートが使用されます。",
"Properties": {
"id": ""
}
}
]
}
]
}
]
}
]
},
{
"ID": "20240610233629-c2bncke",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-c2bncke",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-c02853s",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-c02853s",
"updated": "20240610233629"
},
"Children": [
{
"Type": "NodeText",
"Data": "公開サービスにアクセス制限を設定する場合",
"Properties": {
"id": ""
}
}
]
},
{
"ID": "20240610233629-a5alsxq",
"Type": "NodeList",
"ListData": {
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-a5alsxq",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-4p8jyop",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-4p8jyop",
"updated": "20240610235142"
},
"Children": [
{
"ID": "20240610233629-6pki0nz",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-6pki0nz",
"updated": "20240610235142"
},
"Children": [
{
"Type": "NodeText",
"Data": ""
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "認証アカウント"
},
{
"Type": "NodeText",
"Data": " を追加し、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "サービスの基本認証"
},
{
"Type": "NodeText",
"Data": " スイッチをオンにします。"
}
]
}
]
},
{
"ID": "20240610233629-3s2kd31",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-3s2kd31",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-fozs5am",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-fozs5am",
"updated": "20240610233721"
},
"Children": [
{
"Type": "NodeText",
"Data": "この後、公開サービスはアクセスするユーザーを ",
"Properties": {
"id": ""
}
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "a",
"TextMarkAHref": "https://developer.mozilla.org/ja/docs/Web/HTTP/Authentication#basic_認証方式",
"TextMarkTextContent": "Basic 認証方式"
},
{
"Type": "NodeText",
"Data": " を使用して認証します。",
"Properties": {
"id": ""
}
}
]
},
{
"ID": "20240610233629-b18hlwj",
"Type": "NodeList",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-b18hlwj",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-4mziigo",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-4mziigo",
"updated": "20240610235250"
},
"Children": [
{
"ID": "20240610233629-526pequ",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-526pequ",
"updated": "20240610235250"
},
"Children": [
{
"Type": "NodeText",
"Data": "ユーザーは、公開コンテンツを閲覧する前に、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "認証アカウント"
},
{
"Type": "NodeText",
"Data": " で設定したユーザー名とパスワードを正しく入力する必要があります。"
}
]
}
]
}
]
}
]
}
]
}
]
},
{
"ID": "20240610233629-a4d5gct",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-a4d5gct",
"updated": "20240610234926"
},
"Children": [
{
"ID": "20240610233629-cqspvm0",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-cqspvm0",
"updated": "20240610234926"
},
"Children": [
{
"Type": "NodeText",
"Data": ""
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "サービスを公開する"
},
{
"Type": "NodeText",
"Data": " スイッチをオンにします"
}
]
}
]
}
]
},
{
"ID": "20240610233629-ns08k8s",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240610233629-ns08k8s",
"updated": "20240610235147"
},
"Children": [
{
"Type": "NodeHeadingC8hMarker",
"Data": "## ",
"Properties": {
"id": ""
}
},
{
"Type": "NodeText",
"Data": "",
"Properties": {
"id": ""
}
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "tag",
"TextMarkTextContent": "注意事項"
},
{
"Type": "NodeText",
"Data": "",
"Properties": {
"id": ""
}
}
]
},
{
"ID": "20240610233629-uqp9rz9",
"Type": "NodeList",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-uqp9rz9",
"updated": "20240610235147"
},
"Children": [
{
"ID": "20240610233629-jiv7u6m",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-jiv7u6m",
"updated": "20240610233629"
},
"Children": [
{
"ID": "20240610233629-j8ancdr",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-j8ancdr",
"updated": "20240610233629"
},
"Children": [
{
"Type": "NodeText",
"Data": "公開サービスを開始すると、訪問者はワークスペースの全コンテンツを閲覧できます。",
"Properties": {
"id": ""
}
}
]
}
]
},
{
"ID": "20240610233629-10tmo1g",
"Type": "NodeListItem",
"Data": "*",
"ListData": {
"Tight": true,
"BulletChar": 42,
"Padding": 2,
"Marker": "Kg==",
"Num": -1
},
"Properties": {
"id": "20240610233629-10tmo1g",
"updated": "20240610235147"
},
"Children": [
{
"ID": "20240610233629-20lo5k4",
"Type": "NodeParagraph",
"Properties": {
"id": "20240610233629-20lo5k4",
"updated": "20240610235147"
},
"Children": [
{
"Type": "NodeText",
"Data": ""
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "サービスの基本認証"
},
{
"Type": "NodeText",
"Data": " を無効にすると、すべての訪問者はワークスペースの全コンテンツを認証なしで閲覧できます。"
}
]
}
]
}
]
}
]
}

View file

@ -310,10 +310,12 @@ export const editor = {
if (fontFamilyElement.tagName === "SELECT") {
let fontFamilyHTML = `<option value="">${window.siyuan.languages.default}</option>`;
fetchPost("/api/system/getSysFonts", {}, (response) => {
response.data.forEach((item: string) => {
fontFamilyHTML += `<option value="${item}"${window.siyuan.config.editor.fontFamily === item ? " selected" : ""}>${item}</option>`;
});
fontFamilyElement.innerHTML = fontFamilyHTML;
if (response.code === 0) {
response.data.forEach((item: string) => {
fontFamilyHTML += `<option value="${item}"${window.siyuan.config.editor.fontFamily === item ? " selected" : ""}>${item}</option>`;
});
fontFamilyElement.innerHTML = fontFamilyHTML;
}
});
}
editor.element.querySelector("#clearHistory").addEventListener("click", () => {

View file

@ -13,6 +13,7 @@ import {query} from "./query";
import {Dialog} from "../dialog";
import {ai} from "./ai";
import {flashcard} from "./flashcard";
import {publish} from "./publish";
import {App} from "../index";
import {isHuawei} from "../protyle/util/compatibility";
import {Constants} from "../constants";
@ -79,6 +80,11 @@ export const genItemPanel = (type: string, containerElement: Element, app: App)
query.element = containerElement;
query.bindEvent();
break;
case "publish":
containerElement.innerHTML = publish.genHTML();
publish.element = containerElement;
publish.bindEvent();
break;
default:
break;
}
@ -115,6 +121,7 @@ export const openSetting = (app: App) => {
<li data-name="keymap" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconKeymap"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.keymap}</span></li>
<li data-name="account" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconAccount"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.account}</span></li>
<li data-name="repos" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconCloud"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.cloud}</span></li>
<li data-name="publish" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconLanguage"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.publish}</span></li>
<li data-name="about" class="b3-list-item"><svg class="b3-list-item__graphic"><use xlink:href="#iconInfo"></use></svg><span class="b3-list-item__text">${window.siyuan.languages.about}</span></li>
</ul>
<div class="config__tab-wrap">
@ -131,6 +138,7 @@ export const openSetting = (app: App) => {
<div class="config__tab-container fn__none" style="overflow: scroll" data-name="keymap"></div>
<div class="config__tab-container config__tab-container--full fn__none" data-name="account"></div>
<div class="config__tab-container fn__none" data-name="repos"></div>
<div class="config__tab-container fn__none" data-name="publish"></div>
<div class="config__tab-container fn__none" data-name="about"></div>
<div class="fn__hr--b"></div>
</div>

213
app/src/config/publish.ts Normal file
View file

@ -0,0 +1,213 @@
import {hasClosestByMatchTag} from "../protyle/util/hasClosest";
import {fetchPost} from "../util/fetch";
export const publish = {
element: undefined as Element,
genHTML: () => {
return `
<!-- publish service -->
<label class="fn__flex b3-label">
<div class="fn__flex-1">
${window.siyuan.languages.publishService}
<div class="b3-label__text">${window.siyuan.languages.publishServiceTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="publishEnable" type="checkbox"${window.siyuan.config.publish.enable ? " checked" : ""}/>
</label>
<div class="b3-label">
<!-- publish service port -->
<div class="fn__flex">
<div class="fn__flex-1">
${window.siyuan.languages.publishServicePort}
<div class="b3-label__text">${window.siyuan.languages.publishServicePortTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-text-field fn__flex-center fn__size200" id="publishPort" type="number" min="0" max="65535" value="${window.siyuan.config.publish.port}">
</div>
<!-- publish service address list -->
<div class="b3-label">
<div class="fn__flex config__item">
<div class="fn__flex-1">
${window.siyuan.languages.publishServiceAddresses}
<div class="b3-label__text">${window.siyuan.languages.publishServiceAddressesTip}</div>
</div>
<div class="fn__space"></div>
</div>
<div class="b3-label" id="publishAddresses">
</div>
</div>
</div>
<div class="b3-label">
<!-- publish service auth -->
<label class="fn__flex">
<div class="fn__flex-1">
${window.siyuan.languages.publishServiceAuth}
<div class="b3-label__text">${window.siyuan.languages.publishServiceAuthTip}</div>
</div>
<span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="publishAuthEnable" type="checkbox"${window.siyuan.config.publish.auth.enable ? " checked" : ""}/>
</label>
<!-- publish service auth accounts -->
<div class="b3-label">
<div class="fn__flex config__item">
<div class="fn__flex-1">
${window.siyuan.languages.publishServiceAuthAccounts}
<div class="b3-label__text">${window.siyuan.languages.publishServiceAuthAccountsTip}</div>
</div>
<div class="fn__space"></div>
<button class="b3-button b3-button--outline fn__size200 fn__flex-center" id="publishAuthAccountAdd">
<svg><use xlink:href="#iconAdd"></use></svg>${window.siyuan.languages.publishServiceAuthAccountAdd}
</button>
</div>
<div class="fn__flex" id="publishAuthAccounts">
</div>
</div>
</div>
`;
},
bindEvent: () => {
const publishAuthAccountAdd = publish.element.querySelector<HTMLButtonElement>("#publishAuthAccountAdd");
/* add account */
publishAuthAccountAdd.addEventListener("click", () => {
window.siyuan.config.publish.auth.accounts.push({
username: "",
password: "",
memo: "",
});
publish._renderPublishAuthAccounts(publish.element);
});
/* input change */
publish.element.querySelectorAll("input").forEach(item => {
item.addEventListener("change", () => {
publish._savePublish();
});
});
publish._refreshPublish();
},
_refreshPublish: () => {
fetchPost("/api/setting/getPublish", {}, publish._updatePublishConfig.bind(null, true));
},
_savePublish: (reloadAccounts = true) => {
const publishEnable = publish.element.querySelector<HTMLInputElement>("#publishEnable");
const publishPort = publish.element.querySelector<HTMLInputElement>("#publishPort");
const publishAuthEnable = publish.element.querySelector<HTMLInputElement>("#publishAuthEnable");
fetchPost("/api/setting/setPublish", {
enable: publishEnable.checked,
port: publishPort.valueAsNumber,
auth: {
enable: publishAuthEnable.checked,
accounts: window.siyuan.config.publish.auth.accounts,
} as Config.IPublishAuth,
} as Config.IPublish, publish._updatePublishConfig.bind(null, reloadAccounts));
},
_updatePublishConfig: (
reloadAccounts: boolean,
response: IWebSocketData,
) => {
if (response.code === 0) {
window.siyuan.config.publish = response.data.publish;
reloadAccounts && publish._renderPublishAuthAccounts(publish.element);
publish._renderPublishAddressList(publish.element, response.data.port);
} else {
publish._renderPublishAddressList(publish.element, 0);
}
},
_renderPublishAuthAccounts: (
element: Element,
accounts: Config.IPublishAuthAccount[] = window.siyuan.config.publish.auth.accounts,
) => {
const publishAuthAccounts = element.querySelector<HTMLDivElement>("#publishAuthAccounts");
publishAuthAccounts.innerHTML = `<ul class="fn__flex-1" style="margin-top: 16px">${
accounts
.map((account, index) => `
<li class="b3-label--inner fn__flex" data-index="${index}">
<input class="b3-text-field fn__block" data-name="username" value="${account.username}" placeholder="${window.siyuan.languages.userName}">
<span class="fn__space"></span>
<div class="b3-form__icona fn__block">
<input class="b3-text-field fn__block b3-form__icona-input" type="password" data-name="password" value="${account.password}" placeholder="${window.siyuan.languages.password}">
<svg class="b3-form__icona-icon" data-action="togglePassword"><use xlink:href="#iconEye"></use></svg>
</div>
<span class="fn__space"></span>
<input class="b3-text-field fn__block" data-name="memo" value="${account.memo}" placeholder="${window.siyuan.languages.memo}">
<span class="fn__space"></span>
<span data-action="remove" class="block__icon block__icon--show">
<svg><use xlink:href="#iconTrashcan"></use></svg>
</span>
</li>`
)
.join("")
}</ul>`;
/* account field changed */
publishAuthAccounts
.querySelectorAll("input")
.forEach(input => {
input.addEventListener("change", () => {
const li = hasClosestByMatchTag(input, "LI");
if (li) {
const index = parseInt(li.dataset.index);
const name = input.dataset.name as keyof Config.IPublishAuthAccount;
if (name in window.siyuan.config.publish.auth.accounts[index]) {
window.siyuan.config.publish.auth.accounts[index][name] = input.value;
publish._savePublish(false);
}
}
});
});
/* delete account */
publishAuthAccounts
.querySelectorAll('.block__icon[data-action="remove"]')
.forEach(remove => {
remove.addEventListener("click", () => {
const li = hasClosestByMatchTag(remove, "LI");
if (li) {
const index = parseInt(li.dataset.index);
window.siyuan.config.publish.auth.accounts.splice(index, 1);
publish._savePublish();
}
});
});
/* Toggle the password display status */
publishAuthAccounts
.querySelectorAll('.b3-form__icona-icon[data-action="togglePassword"]')
.forEach(togglePassword => {
togglePassword.addEventListener("click", () => {
const isEye = togglePassword.firstElementChild.getAttribute("xlink:href") === "#iconEye";
togglePassword.firstElementChild.setAttribute("xlink:href", isEye ? "#iconEyeoff" : "#iconEye");
togglePassword.previousElementSibling.setAttribute("type", isEye ? "text" : "password");
});
});
},
_renderPublishAddressList: (
element: Element,
port: number,
) => {
const publishAddresses = element.querySelector<HTMLDivElement>("#publishAddresses");
if (port === 0) {
publishAddresses.innerText = window.siyuan.languages.publishServiceNotStarted;
} else {
publishAddresses.innerHTML = `<ul class="b3-list b3-list--background fn__flex-1">${
window.siyuan.config.localIPs
.filter(ip => !(ip.startsWith("[") && ip.endsWith("]")))
.map(ip => `<li><code class="fn__code">${ip}:${port}</code></li>`)
.join("")
}${
window.siyuan.config.localIPs
.filter(ip => (ip.startsWith("[") && ip.endsWith("]")))
.map(ip => `<li><code class="fn__code">${ip}:${port}</code></li>`)
.join("")
}</ul>`;
}
},
}

View file

@ -169,13 +169,17 @@ const dockToJSON = (dock: Dock) => {
};
export const resetLayout = () => {
fetchPost("/api/system/setUILayout", {layout: {}}, () => {
window.siyuan.storage[Constants.LOCAL_FILEPOSITION] = {};
setStorageVal(Constants.LOCAL_FILEPOSITION, window.siyuan.storage[Constants.LOCAL_FILEPOSITION]);
window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION] = {};
setStorageVal(Constants.LOCAL_DIALOGPOSITION, window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION]);
if (window.siyuan.config.readonly) {
window.location.reload();
});
} else {
fetchPost("/api/system/setUILayout", {layout: {}}, () => {
window.siyuan.storage[Constants.LOCAL_FILEPOSITION] = {};
setStorageVal(Constants.LOCAL_FILEPOSITION, window.siyuan.storage[Constants.LOCAL_FILEPOSITION]);
window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION] = {};
setStorageVal(Constants.LOCAL_DIALOGPOSITION, window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION]);
window.location.reload();
});
}
};
let saveCount = 0;
@ -211,10 +215,12 @@ export const saveLayout = () => {
if (isWindow()) {
sessionStorage.setItem("layout", JSON.stringify(layoutJSON));
} else {
fetchPost("/api/system/setUILayout", {
layout: layoutJSON,
errorExit: false // 后台不接受该参数,用于请求发生错误时退出程序
});
if (!window.siyuan.config.readonly) {
fetchPost("/api/system/setUILayout", {
layout: layoutJSON,
errorExit: false // 后台不接受该参数,用于请求发生错误时退出程序
});
}
}
}
};
@ -250,12 +256,17 @@ export const exportLayout = (options: {
getAllModels().editor.forEach(item => {
saveScroll(item.editor.protyle);
});
fetchPost("/api/system/setUILayout", {
layout: layoutJSON,
errorExit: options.errorExit // 后台不接受该参数,用于请求发生错误时退出程序
}, () => {
if (window.siyuan.config.readonly) {
options.cb();
});
} else {
fetchPost("/api/system/setUILayout", {
layout: layoutJSON,
errorExit: options.errorExit // 后台不接受该参数,用于请求发生错误时退出程序
}, () => {
options.cb();
});
}
};
export const getAllLayout = () => {

View file

@ -507,8 +507,9 @@ export const exportMd = (id: string) => {
});
});
return;
} else if (response.code === 0) {
showMessage(window.siyuan.languages.exportTplSucc);
}
showMessage(window.siyuan.languages.exportTplSucc);
});
dialog.destroy();
});

View file

@ -340,9 +340,13 @@ export const workspaceMenu = (app: App, rect: DOMRect) => {
window.siyuan.menus.menu.remove();
return;
}
fetchPost("/api/system/setUILayout", {layout: item.layout}, () => {
if (window.siyuan.config.readonly) {
window.location.reload();
});
} else {
fetchPost("/api/system/setUILayout", {layout: item.layout}, () => {
window.location.reload();
});
}
});
}
});

View file

@ -287,6 +287,10 @@ export const getLocalStorage = (cb: () => void) => {
};
export const setStorageVal = (key: string, val: any) => {
if (window.siyuan.config.readonly) {
return;
}
fetchPost("/api/storage/setLocalStorageVal", {
app: Constants.SIYUAN_APPID,
key,

View file

@ -63,6 +63,11 @@ declare namespace Config {
* Whether to open the user guide after startup
*/
openHelp: boolean;
/**
* Publishing service
*
*/
publish: IPublish;
/**
* Whether it is running in read-only mode
*
@ -1030,6 +1035,56 @@ declare namespace Config {
*/
export type TLogLevel = "off" | "trace" | "debug" | "info" | "warn" | "error" | "fatal";
/**
* Publishing service
*/
export interface IPublish {
/**
* Whether to open the publishing service
*/
enable: boolean;
/**
* The basic authentication settings of publishing service
*/
auth: IPublishAuth;
/**
* Port on which the publishing service listens
*/
port: number;
}
/**
* Publishing service authentication settings
*/
export interface IPublishAuth {
/**
* Whether to enable basic authentication for publishing services
*/
enable: boolean;
/**
* List of basic verified accounts
*/
accounts: IPublishAuthAccount[];
}
/**
* Basic authentication account
*/
export interface IPublishAuthAccount {
/**
* Account username
*/
username: string;
/**
* Account password
*/
password: string;
/**
* The memo text of the account
*/
memo: string;
}
/**
* Snapshot repository related configuration
*/

View file

@ -150,8 +150,10 @@ export const initAssets = () => {
return;
}
}
window.siyuan.config.appearance = response.data.appearance;
loadAssets(response.data.appearance);
if (response.code === 0) {
window.siyuan.config.appearance = response.data.appearance;
loadAssets(response.data.appearance);
}
});
});
};

View file

@ -32,18 +32,20 @@ export const fetchPost = (url: string, data?: any, cb?: (response: IWebSocketDat
init.headers = headers;
}
fetch(url, init).then((response) => {
if (response.status === 404) {
return {
data: null,
msg: response.statusText,
code: response.status,
};
} else {
if (response.headers.get("content-type")?.indexOf("application/json") > -1) {
return response.json();
} else {
return response.text();
}
switch (response.status) {
case 403:
case 404:
return {
data: null,
msg: response.statusText,
code: response.status,
};
default:
if (response.headers.get("content-type")?.indexOf("application/json") > -1) {
return response.json();
} else {
return response.text();
}
}
}).then((response: IWebSocketData) => {
if (typeof response === "string") {

View file

@ -166,13 +166,31 @@ func getFile(c *gin.Context) {
return
}
if info.IsDir() {
logging.LogErrorf("file [%s] is a directory", fileAbsPath)
logging.LogErrorf("path [%s] is a directory path", fileAbsPath)
ret.Code = http.StatusMethodNotAllowed
ret.Msg = "file is a directory"
ret.Msg = "This is a directory path"
c.JSON(http.StatusAccepted, ret)
return
}
// REF: https://github.com/siyuan-note/siyuan/issues/11364
if role := model.GetGinContextRole(c); !model.IsValidRole(role, []model.Role{
model.RoleAdministrator,
}) {
if relPath, err := filepath.Rel(util.ConfDir, fileAbsPath); err != nil {
logging.LogErrorf("Get a relative path from [%s] to [%s] failed: %s", util.ConfDir, fileAbsPath, err)
ret.Code = http.StatusInternalServerError
ret.Msg = err.Error()
c.JSON(http.StatusAccepted, ret)
return
} else if relPath == "conf.json" {
ret.Code = http.StatusForbidden
ret.Msg = http.StatusText(http.StatusForbidden)
c.JSON(http.StatusAccepted, ret)
return
}
}
data, err := filelock.ReadFile(fileAbsPath)
if nil != err {
logging.LogErrorf("read file [%s] failed: %s", fileAbsPath, err)

View file

@ -33,122 +33,121 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/system/loginAuth", model.LoginAuth)
ginServer.Handle("POST", "/api/system/logoutAuth", model.LogoutAuth)
ginServer.Handle("GET", "/api/system/getCaptcha", model.GetCaptcha)
ginServer.Handle("POST", "/api/system/setUILayout", setUILayout) // 这里不加鉴权 After modifying the access authentication code on the browser side, the other side does not refresh https://github.com/siyuan-note/siyuan/issues/8028
ginServer.Handle("GET", "/snippets/*filepath", serveSnippets)
// 需要鉴权
ginServer.Handle("POST", "/api/system/getEmojiConf", model.CheckAuth, getEmojiConf)
ginServer.Handle("POST", "/api/system/setAPIToken", model.CheckAuth, model.CheckReadonly, setAPIToken)
ginServer.Handle("POST", "/api/system/setAccessAuthCode", model.CheckAuth, model.CheckReadonly, setAccessAuthCode)
ginServer.Handle("POST", "/api/system/setFollowSystemLockScreen", model.CheckAuth, model.CheckReadonly, setFollowSystemLockScreen)
ginServer.Handle("POST", "/api/system/setNetworkServe", model.CheckAuth, model.CheckReadonly, setNetworkServe)
ginServer.Handle("POST", "/api/system/setUploadErrLog", model.CheckAuth, model.CheckReadonly, setUploadErrLog)
ginServer.Handle("POST", "/api/system/setAutoLaunch", model.CheckAuth, model.CheckReadonly, setAutoLaunch)
ginServer.Handle("POST", "/api/system/setGoogleAnalytics", model.CheckAuth, model.CheckReadonly, setGoogleAnalytics)
ginServer.Handle("POST", "/api/system/setDownloadInstallPkg", model.CheckAuth, model.CheckReadonly, setDownloadInstallPkg)
ginServer.Handle("POST", "/api/system/setNetworkProxy", model.CheckAuth, model.CheckReadonly, setNetworkProxy)
ginServer.Handle("POST", "/api/system/setWorkspaceDir", model.CheckAuth, model.CheckReadonly, setWorkspaceDir)
ginServer.Handle("POST", "/api/system/getWorkspaces", model.CheckAuth, getWorkspaces)
ginServer.Handle("POST", "/api/system/getMobileWorkspaces", model.CheckAuth, getMobileWorkspaces)
ginServer.Handle("POST", "/api/system/checkWorkspaceDir", model.CheckAuth, model.CheckReadonly, checkWorkspaceDir)
ginServer.Handle("POST", "/api/system/createWorkspaceDir", model.CheckAuth, model.CheckReadonly, createWorkspaceDir)
ginServer.Handle("POST", "/api/system/removeWorkspaceDir", model.CheckAuth, model.CheckReadonly, removeWorkspaceDir)
ginServer.Handle("POST", "/api/system/removeWorkspaceDirPhysically", model.CheckAuth, model.CheckReadonly, removeWorkspaceDirPhysically)
ginServer.Handle("POST", "/api/system/setAppearanceMode", model.CheckAuth, setAppearanceMode)
ginServer.Handle("POST", "/api/system/getSysFonts", model.CheckAuth, getSysFonts)
ginServer.Handle("POST", "/api/system/exit", model.CheckAuth, exit)
ginServer.Handle("POST", "/api/system/setAPIToken", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAPIToken)
ginServer.Handle("POST", "/api/system/setAccessAuthCode", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAccessAuthCode)
ginServer.Handle("POST", "/api/system/setFollowSystemLockScreen", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setFollowSystemLockScreen)
ginServer.Handle("POST", "/api/system/setNetworkServe", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNetworkServe)
ginServer.Handle("POST", "/api/system/setUploadErrLog", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setUploadErrLog)
ginServer.Handle("POST", "/api/system/setAutoLaunch", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAutoLaunch)
ginServer.Handle("POST", "/api/system/setGoogleAnalytics", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setGoogleAnalytics)
ginServer.Handle("POST", "/api/system/setDownloadInstallPkg", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setDownloadInstallPkg)
ginServer.Handle("POST", "/api/system/setNetworkProxy", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNetworkProxy)
ginServer.Handle("POST", "/api/system/setWorkspaceDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setWorkspaceDir)
ginServer.Handle("POST", "/api/system/getWorkspaces", model.CheckAuth, model.CheckAdminRole, getWorkspaces)
ginServer.Handle("POST", "/api/system/getMobileWorkspaces", model.CheckAuth, model.CheckAdminRole, getMobileWorkspaces)
ginServer.Handle("POST", "/api/system/checkWorkspaceDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, checkWorkspaceDir)
ginServer.Handle("POST", "/api/system/createWorkspaceDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createWorkspaceDir)
ginServer.Handle("POST", "/api/system/removeWorkspaceDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeWorkspaceDir)
ginServer.Handle("POST", "/api/system/removeWorkspaceDirPhysically", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeWorkspaceDirPhysically)
ginServer.Handle("POST", "/api/system/setAppearanceMode", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAppearanceMode)
ginServer.Handle("POST", "/api/system/setUILayout", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setUILayout)
ginServer.Handle("POST", "/api/system/getSysFonts", model.CheckAuth, model.CheckAdminRole, getSysFonts)
ginServer.Handle("POST", "/api/system/exit", model.CheckAuth, model.CheckAdminRole, exit)
ginServer.Handle("POST", "/api/system/getConf", model.CheckAuth, getConf)
ginServer.Handle("POST", "/api/system/checkUpdate", model.CheckAuth, checkUpdate)
ginServer.Handle("POST", "/api/system/exportLog", model.CheckAuth, exportLog)
ginServer.Handle("POST", "/api/system/checkUpdate", model.CheckAuth, model.CheckAdminRole, checkUpdate)
ginServer.Handle("POST", "/api/system/exportLog", model.CheckAuth, model.CheckAdminRole, exportLog)
ginServer.Handle("POST", "/api/system/getChangelog", model.CheckAuth, getChangelog)
ginServer.Handle("POST", "/api/system/getNetwork", model.CheckAuth, getNetwork)
ginServer.Handle("POST", "/api/system/getNetwork", model.CheckAuth, model.CheckAdminRole, getNetwork)
ginServer.Handle("POST", "/api/storage/setLocalStorage", model.CheckAuth, model.CheckReadonly, setLocalStorage)
ginServer.Handle("POST", "/api/storage/setLocalStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setLocalStorage)
ginServer.Handle("POST", "/api/storage/getLocalStorage", model.CheckAuth, getLocalStorage)
ginServer.Handle("POST", "/api/storage/setLocalStorageVal", model.CheckAuth, model.CheckReadonly, setLocalStorageVal)
ginServer.Handle("POST", "/api/storage/removeLocalStorageVals", model.CheckAuth, model.CheckReadonly, removeLocalStorageVals)
ginServer.Handle("POST", "/api/storage/setCriterion", model.CheckAuth, model.CheckReadonly, setCriterion)
ginServer.Handle("POST", "/api/storage/setLocalStorageVal", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setLocalStorageVal)
ginServer.Handle("POST", "/api/storage/removeLocalStorageVals", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeLocalStorageVals)
ginServer.Handle("POST", "/api/storage/setCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setCriterion)
ginServer.Handle("POST", "/api/storage/getCriteria", model.CheckAuth, getCriteria)
ginServer.Handle("POST", "/api/storage/removeCriterion", model.CheckAuth, model.CheckReadonly, removeCriterion)
ginServer.Handle("POST", "/api/storage/removeCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeCriterion)
ginServer.Handle("POST", "/api/storage/getRecentDocs", model.CheckAuth, getRecentDocs)
ginServer.Handle("POST", "/api/account/login", model.CheckAuth, model.CheckReadonly, login)
ginServer.Handle("POST", "/api/account/checkActivationcode", model.CheckAuth, model.CheckReadonly, checkActivationcode)
ginServer.Handle("POST", "/api/account/useActivationcode", model.CheckAuth, model.CheckReadonly, useActivationcode)
ginServer.Handle("POST", "/api/account/deactivate", model.CheckAuth, model.CheckReadonly, deactivateUser)
ginServer.Handle("POST", "/api/account/startFreeTrial", model.CheckAuth, model.CheckReadonly, startFreeTrial)
ginServer.Handle("POST", "/api/account/login", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, login)
ginServer.Handle("POST", "/api/account/checkActivationcode", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, checkActivationcode)
ginServer.Handle("POST", "/api/account/useActivationcode", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, useActivationcode)
ginServer.Handle("POST", "/api/account/deactivate", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, deactivateUser)
ginServer.Handle("POST", "/api/account/startFreeTrial", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, startFreeTrial)
ginServer.Handle("POST", "/api/notebook/lsNotebooks", model.CheckAuth, lsNotebooks)
ginServer.Handle("POST", "/api/notebook/openNotebook", model.CheckAuth, model.CheckReadonly, openNotebook)
ginServer.Handle("POST", "/api/notebook/closeNotebook", model.CheckAuth, model.CheckReadonly, closeNotebook)
ginServer.Handle("POST", "/api/notebook/openNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, openNotebook)
ginServer.Handle("POST", "/api/notebook/closeNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, closeNotebook)
ginServer.Handle("POST", "/api/notebook/getNotebookConf", model.CheckAuth, getNotebookConf)
ginServer.Handle("POST", "/api/notebook/setNotebookConf", model.CheckAuth, model.CheckReadonly, setNotebookConf)
ginServer.Handle("POST", "/api/notebook/createNotebook", model.CheckAuth, model.CheckReadonly, createNotebook)
ginServer.Handle("POST", "/api/notebook/removeNotebook", model.CheckAuth, model.CheckReadonly, removeNotebook)
ginServer.Handle("POST", "/api/notebook/renameNotebook", model.CheckAuth, model.CheckReadonly, renameNotebook)
ginServer.Handle("POST", "/api/notebook/changeSortNotebook", model.CheckAuth, model.CheckReadonly, changeSortNotebook)
ginServer.Handle("POST", "/api/notebook/setNotebookIcon", model.CheckAuth, model.CheckReadonly, setNotebookIcon)
ginServer.Handle("POST", "/api/notebook/setNotebookConf", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNotebookConf)
ginServer.Handle("POST", "/api/notebook/createNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createNotebook)
ginServer.Handle("POST", "/api/notebook/removeNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeNotebook)
ginServer.Handle("POST", "/api/notebook/renameNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameNotebook)
ginServer.Handle("POST", "/api/notebook/changeSortNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, changeSortNotebook)
ginServer.Handle("POST", "/api/notebook/setNotebookIcon", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNotebookIcon)
ginServer.Handle("POST", "/api/filetree/searchDocs", model.CheckAuth, searchDocs)
ginServer.Handle("POST", "/api/filetree/listDocsByPath", model.CheckAuth, listDocsByPath)
ginServer.Handle("POST", "/api/filetree/getDoc", model.CheckAuth, getDoc)
ginServer.Handle("POST", "/api/filetree/getDocCreateSavePath", model.CheckAuth, getDocCreateSavePath)
ginServer.Handle("POST", "/api/filetree/getRefCreateSavePath", model.CheckAuth, getRefCreateSavePath)
ginServer.Handle("POST", "/api/filetree/changeSort", model.CheckAuth, model.CheckReadonly, changeSort)
ginServer.Handle("POST", "/api/filetree/createDocWithMd", model.CheckAuth, model.CheckReadonly, createDocWithMd)
ginServer.Handle("POST", "/api/filetree/createDailyNote", model.CheckAuth, model.CheckReadonly, createDailyNote)
ginServer.Handle("POST", "/api/filetree/createDoc", model.CheckAuth, model.CheckReadonly, createDoc)
ginServer.Handle("POST", "/api/filetree/renameDoc", model.CheckAuth, model.CheckReadonly, renameDoc)
ginServer.Handle("POST", "/api/filetree/removeDoc", model.CheckAuth, model.CheckReadonly, removeDoc)
ginServer.Handle("POST", "/api/filetree/removeDocs", model.CheckAuth, model.CheckReadonly, removeDocs)
ginServer.Handle("POST", "/api/filetree/moveDocs", model.CheckAuth, model.CheckReadonly, moveDocs)
ginServer.Handle("POST", "/api/filetree/duplicateDoc", model.CheckAuth, model.CheckReadonly, duplicateDoc)
ginServer.Handle("POST", "/api/filetree/changeSort", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, changeSort)
ginServer.Handle("POST", "/api/filetree/createDocWithMd", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createDocWithMd)
ginServer.Handle("POST", "/api/filetree/createDailyNote", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createDailyNote)
ginServer.Handle("POST", "/api/filetree/createDoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createDoc)
ginServer.Handle("POST", "/api/filetree/renameDoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameDoc)
ginServer.Handle("POST", "/api/filetree/removeDoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeDoc)
ginServer.Handle("POST", "/api/filetree/removeDocs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeDocs)
ginServer.Handle("POST", "/api/filetree/moveDocs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, moveDocs)
ginServer.Handle("POST", "/api/filetree/duplicateDoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, duplicateDoc)
ginServer.Handle("POST", "/api/filetree/getHPathByPath", model.CheckAuth, getHPathByPath)
ginServer.Handle("POST", "/api/filetree/getHPathsByPaths", model.CheckAuth, getHPathsByPaths)
ginServer.Handle("POST", "/api/filetree/getHPathByID", model.CheckAuth, getHPathByID)
ginServer.Handle("POST", "/api/filetree/getFullHPathByID", model.CheckAuth, getFullHPathByID)
ginServer.Handle("POST", "/api/filetree/getIDsByHPath", model.CheckAuth, getIDsByHPath)
ginServer.Handle("POST", "/api/filetree/doc2Heading", model.CheckAuth, model.CheckReadonly, doc2Heading)
ginServer.Handle("POST", "/api/filetree/heading2Doc", model.CheckAuth, model.CheckReadonly, heading2Doc)
ginServer.Handle("POST", "/api/filetree/li2Doc", model.CheckAuth, model.CheckReadonly, li2Doc)
ginServer.Handle("POST", "/api/filetree/refreshFiletree", model.CheckAuth, model.CheckReadonly, refreshFiletree)
ginServer.Handle("POST", "/api/filetree/upsertIndexes", model.CheckAuth, model.CheckReadonly, upsertIndexes)
ginServer.Handle("POST", "/api/filetree/removeIndexes", model.CheckAuth, model.CheckReadonly, removeIndexes)
ginServer.Handle("POST", "/api/filetree/listDocTree", model.CheckAuth, model.CheckReadonly, listDocTree)
ginServer.Handle("POST", "/api/filetree/doc2Heading", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, doc2Heading)
ginServer.Handle("POST", "/api/filetree/heading2Doc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, heading2Doc)
ginServer.Handle("POST", "/api/filetree/li2Doc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, li2Doc)
ginServer.Handle("POST", "/api/filetree/refreshFiletree", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, refreshFiletree)
ginServer.Handle("POST", "/api/filetree/upsertIndexes", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, upsertIndexes)
ginServer.Handle("POST", "/api/filetree/removeIndexes", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeIndexes)
ginServer.Handle("POST", "/api/filetree/listDocTree", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, listDocTree)
ginServer.Handle("POST", "/api/format/autoSpace", model.CheckAuth, model.CheckReadonly, autoSpace)
ginServer.Handle("POST", "/api/format/netImg2LocalAssets", model.CheckAuth, model.CheckReadonly, netImg2LocalAssets)
ginServer.Handle("POST", "/api/format/netAssets2LocalAssets", model.CheckAuth, model.CheckReadonly, netAssets2LocalAssets)
ginServer.Handle("POST", "/api/format/autoSpace", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, autoSpace)
ginServer.Handle("POST", "/api/format/netImg2LocalAssets", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, netImg2LocalAssets)
ginServer.Handle("POST", "/api/format/netAssets2LocalAssets", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, netAssets2LocalAssets)
ginServer.Handle("POST", "/api/history/getNotebookHistory", model.CheckAuth, getNotebookHistory)
ginServer.Handle("POST", "/api/history/rollbackNotebookHistory", model.CheckAuth, model.CheckReadonly, rollbackNotebookHistory)
ginServer.Handle("POST", "/api/history/rollbackAssetsHistory", model.CheckAuth, model.CheckReadonly, rollbackAssetsHistory)
ginServer.Handle("POST", "/api/history/getDocHistoryContent", model.CheckAuth, getDocHistoryContent)
ginServer.Handle("POST", "/api/history/rollbackDocHistory", model.CheckAuth, model.CheckReadonly, rollbackDocHistory)
ginServer.Handle("POST", "/api/history/clearWorkspaceHistory", model.CheckAuth, model.CheckReadonly, clearWorkspaceHistory)
ginServer.Handle("POST", "/api/history/reindexHistory", model.CheckAuth, model.CheckReadonly, reindexHistory)
ginServer.Handle("POST", "/api/history/searchHistory", model.CheckAuth, searchHistory)
ginServer.Handle("POST", "/api/history/getHistoryItems", model.CheckAuth, getHistoryItems)
ginServer.Handle("POST", "/api/history/getNotebookHistory", model.CheckAuth, model.CheckAdminRole, getNotebookHistory)
ginServer.Handle("POST", "/api/history/rollbackNotebookHistory", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, rollbackNotebookHistory)
ginServer.Handle("POST", "/api/history/rollbackAssetsHistory", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, rollbackAssetsHistory)
ginServer.Handle("POST", "/api/history/getDocHistoryContent", model.CheckAuth, model.CheckAdminRole, getDocHistoryContent)
ginServer.Handle("POST", "/api/history/rollbackDocHistory", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, rollbackDocHistory)
ginServer.Handle("POST", "/api/history/clearWorkspaceHistory", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, clearWorkspaceHistory)
ginServer.Handle("POST", "/api/history/reindexHistory", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reindexHistory)
ginServer.Handle("POST", "/api/history/searchHistory", model.CheckAuth, model.CheckAdminRole, searchHistory)
ginServer.Handle("POST", "/api/history/getHistoryItems", model.CheckAuth, model.CheckAdminRole, getHistoryItems)
ginServer.Handle("POST", "/api/outline/getDocOutline", model.CheckAuth, getDocOutline)
ginServer.Handle("POST", "/api/bookmark/getBookmark", model.CheckAuth, getBookmark)
ginServer.Handle("POST", "/api/bookmark/renameBookmark", model.CheckAuth, model.CheckReadonly, renameBookmark)
ginServer.Handle("POST", "/api/bookmark/removeBookmark", model.CheckAuth, model.CheckReadonly, removeBookmark)
ginServer.Handle("POST", "/api/bookmark/renameBookmark", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameBookmark)
ginServer.Handle("POST", "/api/bookmark/removeBookmark", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeBookmark)
ginServer.Handle("POST", "/api/tag/getTag", model.CheckAuth, getTag)
ginServer.Handle("POST", "/api/tag/renameTag", model.CheckAuth, model.CheckReadonly, renameTag)
ginServer.Handle("POST", "/api/tag/removeTag", model.CheckAuth, model.CheckReadonly, removeTag)
ginServer.Handle("POST", "/api/tag/renameTag", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameTag)
ginServer.Handle("POST", "/api/tag/removeTag", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeTag)
ginServer.Handle("POST", "/api/lute/spinBlockDOM", model.CheckAuth, spinBlockDOM) // 未测试
ginServer.Handle("POST", "/api/lute/html2BlockDOM", model.CheckAuth, html2BlockDOM)
ginServer.Handle("POST", "/api/lute/copyStdMarkdown", model.CheckAuth, copyStdMarkdown)
ginServer.Handle("POST", "/api/query/sql", model.CheckAuth, SQL)
ginServer.Handle("POST", "/api/sqlite/flushTransaction", model.CheckAuth, model.CheckReadonly, flushTransaction)
ginServer.Handle("POST", "/api/sqlite/flushTransaction", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, flushTransaction)
ginServer.Handle("POST", "/api/search/searchTag", model.CheckAuth, searchTag)
ginServer.Handle("POST", "/api/search/searchTemplate", model.CheckAuth, searchTemplate)
ginServer.Handle("POST", "/api/search/removeTemplate", model.CheckAuth, model.CheckReadonly, removeTemplate)
ginServer.Handle("POST", "/api/search/removeTemplate", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeTemplate)
ginServer.Handle("POST", "/api/search/searchWidget", model.CheckAuth, searchWidget)
ginServer.Handle("POST", "/api/search/searchRefBlock", model.CheckAuth, searchRefBlock)
ginServer.Handle("POST", "/api/search/searchEmbedBlock", model.CheckAuth, searchEmbedBlock)
@ -181,33 +180,33 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/block/getDocInfo", model.CheckAuth, getDocInfo)
ginServer.Handle("POST", "/api/block/checkBlockExist", model.CheckAuth, checkBlockExist)
ginServer.Handle("POST", "/api/block/checkBlockFold", model.CheckAuth, checkBlockFold)
ginServer.Handle("POST", "/api/block/insertBlock", model.CheckAuth, model.CheckReadonly, insertBlock)
ginServer.Handle("POST", "/api/block/prependBlock", model.CheckAuth, model.CheckReadonly, prependBlock)
ginServer.Handle("POST", "/api/block/appendBlock", model.CheckAuth, model.CheckReadonly, appendBlock)
ginServer.Handle("POST", "/api/block/appendDailyNoteBlock", model.CheckAuth, model.CheckReadonly, appendDailyNoteBlock)
ginServer.Handle("POST", "/api/block/prependDailyNoteBlock", model.CheckAuth, model.CheckReadonly, prependDailyNoteBlock)
ginServer.Handle("POST", "/api/block/updateBlock", model.CheckAuth, model.CheckReadonly, updateBlock)
ginServer.Handle("POST", "/api/block/deleteBlock", model.CheckAuth, model.CheckReadonly, deleteBlock)
ginServer.Handle("POST", "/api/block/moveBlock", model.CheckAuth, model.CheckReadonly, moveBlock)
ginServer.Handle("POST", "/api/block/moveOutlineHeading", model.CheckAuth, model.CheckReadonly, moveOutlineHeading)
ginServer.Handle("POST", "/api/block/foldBlock", model.CheckAuth, model.CheckReadonly, foldBlock)
ginServer.Handle("POST", "/api/block/unfoldBlock", model.CheckAuth, model.CheckReadonly, unfoldBlock)
ginServer.Handle("POST", "/api/block/setBlockReminder", model.CheckAuth, model.CheckReadonly, setBlockReminder)
ginServer.Handle("POST", "/api/block/insertBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, insertBlock)
ginServer.Handle("POST", "/api/block/prependBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, prependBlock)
ginServer.Handle("POST", "/api/block/appendBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, appendBlock)
ginServer.Handle("POST", "/api/block/appendDailyNoteBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, appendDailyNoteBlock)
ginServer.Handle("POST", "/api/block/prependDailyNoteBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, prependDailyNoteBlock)
ginServer.Handle("POST", "/api/block/updateBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, updateBlock)
ginServer.Handle("POST", "/api/block/deleteBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, deleteBlock)
ginServer.Handle("POST", "/api/block/moveBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, moveBlock)
ginServer.Handle("POST", "/api/block/moveOutlineHeading", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, moveOutlineHeading)
ginServer.Handle("POST", "/api/block/foldBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, foldBlock)
ginServer.Handle("POST", "/api/block/unfoldBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, unfoldBlock)
ginServer.Handle("POST", "/api/block/setBlockReminder", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setBlockReminder)
ginServer.Handle("POST", "/api/block/getHeadingLevelTransaction", model.CheckAuth, getHeadingLevelTransaction)
ginServer.Handle("POST", "/api/block/getHeadingDeleteTransaction", model.CheckAuth, getHeadingDeleteTransaction)
ginServer.Handle("POST", "/api/block/getHeadingChildrenIDs", model.CheckAuth, getHeadingChildrenIDs)
ginServer.Handle("POST", "/api/block/getHeadingChildrenDOM", model.CheckAuth, getHeadingChildrenDOM)
ginServer.Handle("POST", "/api/block/swapBlockRef", model.CheckAuth, model.CheckReadonly, swapBlockRef)
ginServer.Handle("POST", "/api/block/transferBlockRef", model.CheckAuth, model.CheckReadonly, transferBlockRef)
ginServer.Handle("POST", "/api/block/swapBlockRef", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, swapBlockRef)
ginServer.Handle("POST", "/api/block/transferBlockRef", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, transferBlockRef)
ginServer.Handle("POST", "/api/block/getBlockSiblingID", model.CheckAuth, getBlockSiblingID)
ginServer.Handle("POST", "/api/block/getBlockTreeInfos", model.CheckAuth, getBlockTreeInfos)
ginServer.Handle("POST", "/api/file/getFile", model.CheckAuth, getFile)
ginServer.Handle("POST", "/api/file/putFile", model.CheckAuth, model.CheckReadonly, putFile)
ginServer.Handle("POST", "/api/file/copyFile", model.CheckAuth, model.CheckReadonly, copyFile)
ginServer.Handle("POST", "/api/file/globalCopyFiles", model.CheckAuth, model.CheckReadonly, globalCopyFiles)
ginServer.Handle("POST", "/api/file/removeFile", model.CheckAuth, model.CheckReadonly, removeFile)
ginServer.Handle("POST", "/api/file/renameFile", model.CheckAuth, model.CheckReadonly, renameFile)
ginServer.Handle("POST", "/api/file/putFile", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, putFile)
ginServer.Handle("POST", "/api/file/copyFile", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, copyFile)
ginServer.Handle("POST", "/api/file/globalCopyFiles", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, globalCopyFiles)
ginServer.Handle("POST", "/api/file/removeFile", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeFile)
ginServer.Handle("POST", "/api/file/renameFile", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameFile)
ginServer.Handle("POST", "/api/file/readDir", model.CheckAuth, readDir)
ginServer.Handle("POST", "/api/file/getUniqueFilename", model.CheckAuth, getUniqueFilename)
@ -218,57 +217,57 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/ref/getBackmentionDoc", model.CheckAuth, getBackmentionDoc)
ginServer.Handle("POST", "/api/attr/getBookmarkLabels", model.CheckAuth, getBookmarkLabels)
ginServer.Handle("POST", "/api/attr/resetBlockAttrs", model.CheckAuth, model.CheckReadonly, resetBlockAttrs)
ginServer.Handle("POST", "/api/attr/setBlockAttrs", model.CheckAuth, model.CheckReadonly, setBlockAttrs)
ginServer.Handle("POST", "/api/attr/batchSetBlockAttrs", model.CheckAuth, model.CheckReadonly, batchSetBlockAttrs)
ginServer.Handle("POST", "/api/attr/resetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetBlockAttrs)
ginServer.Handle("POST", "/api/attr/setBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setBlockAttrs)
ginServer.Handle("POST", "/api/attr/batchSetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchSetBlockAttrs)
ginServer.Handle("POST", "/api/attr/getBlockAttrs", model.CheckAuth, getBlockAttrs)
ginServer.Handle("POST", "/api/cloud/getCloudSpace", model.CheckAuth, getCloudSpace)
ginServer.Handle("POST", "/api/cloud/getCloudSpace", model.CheckAuth, model.CheckAdminRole, getCloudSpace)
ginServer.Handle("POST", "/api/sync/setSyncEnable", model.CheckAuth, model.CheckReadonly, setSyncEnable)
ginServer.Handle("POST", "/api/sync/setSyncPerception", model.CheckAuth, model.CheckReadonly, setSyncPerception)
ginServer.Handle("POST", "/api/sync/setSyncGenerateConflictDoc", model.CheckAuth, model.CheckReadonly, setSyncGenerateConflictDoc)
ginServer.Handle("POST", "/api/sync/setSyncMode", model.CheckAuth, model.CheckReadonly, setSyncMode)
ginServer.Handle("POST", "/api/sync/setSyncProvider", model.CheckAuth, model.CheckReadonly, setSyncProvider)
ginServer.Handle("POST", "/api/sync/setSyncProviderS3", model.CheckAuth, model.CheckReadonly, setSyncProviderS3)
ginServer.Handle("POST", "/api/sync/setSyncProviderWebDAV", model.CheckAuth, model.CheckReadonly, setSyncProviderWebDAV)
ginServer.Handle("POST", "/api/sync/setCloudSyncDir", model.CheckAuth, model.CheckReadonly, setCloudSyncDir)
ginServer.Handle("POST", "/api/sync/createCloudSyncDir", model.CheckAuth, model.CheckReadonly, createCloudSyncDir)
ginServer.Handle("POST", "/api/sync/removeCloudSyncDir", model.CheckAuth, model.CheckReadonly, removeCloudSyncDir)
ginServer.Handle("POST", "/api/sync/listCloudSyncDir", model.CheckAuth, listCloudSyncDir)
ginServer.Handle("POST", "/api/sync/performSync", model.CheckAuth, model.CheckReadonly, performSync)
ginServer.Handle("POST", "/api/sync/performBootSync", model.CheckAuth, model.CheckReadonly, performBootSync)
ginServer.Handle("POST", "/api/sync/getBootSync", model.CheckAuth, getBootSync)
ginServer.Handle("POST", "/api/sync/getSyncInfo", model.CheckAuth, getSyncInfo)
ginServer.Handle("POST", "/api/sync/exportSyncProviderS3", model.CheckAuth, exportSyncProviderS3)
ginServer.Handle("POST", "/api/sync/importSyncProviderS3", model.CheckAuth, model.CheckReadonly, importSyncProviderS3)
ginServer.Handle("POST", "/api/sync/exportSyncProviderWebDAV", model.CheckAuth, exportSyncProviderWebDAV)
ginServer.Handle("POST", "/api/sync/importSyncProviderWebDAV", model.CheckAuth, model.CheckReadonly, importSyncProviderWebDAV)
ginServer.Handle("POST", "/api/sync/setSyncEnable", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncEnable)
ginServer.Handle("POST", "/api/sync/setSyncPerception", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncPerception)
ginServer.Handle("POST", "/api/sync/setSyncGenerateConflictDoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncGenerateConflictDoc)
ginServer.Handle("POST", "/api/sync/setSyncMode", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncMode)
ginServer.Handle("POST", "/api/sync/setSyncProvider", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncProvider)
ginServer.Handle("POST", "/api/sync/setSyncProviderS3", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncProviderS3)
ginServer.Handle("POST", "/api/sync/setSyncProviderWebDAV", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSyncProviderWebDAV)
ginServer.Handle("POST", "/api/sync/setCloudSyncDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setCloudSyncDir)
ginServer.Handle("POST", "/api/sync/createCloudSyncDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createCloudSyncDir)
ginServer.Handle("POST", "/api/sync/removeCloudSyncDir", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeCloudSyncDir)
ginServer.Handle("POST", "/api/sync/listCloudSyncDir", model.CheckAuth, model.CheckAdminRole, listCloudSyncDir)
ginServer.Handle("POST", "/api/sync/performSync", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, performSync)
ginServer.Handle("POST", "/api/sync/performBootSync", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, performBootSync)
ginServer.Handle("POST", "/api/sync/getBootSync", model.CheckAuth, model.CheckAdminRole, getBootSync)
ginServer.Handle("POST", "/api/sync/getSyncInfo", model.CheckAuth, model.CheckAdminRole, getSyncInfo)
ginServer.Handle("POST", "/api/sync/exportSyncProviderS3", model.CheckAuth, model.CheckAdminRole, exportSyncProviderS3)
ginServer.Handle("POST", "/api/sync/importSyncProviderS3", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importSyncProviderS3)
ginServer.Handle("POST", "/api/sync/exportSyncProviderWebDAV", model.CheckAuth, model.CheckAdminRole, exportSyncProviderWebDAV)
ginServer.Handle("POST", "/api/sync/importSyncProviderWebDAV", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importSyncProviderWebDAV)
ginServer.Handle("POST", "/api/inbox/getShorthands", model.CheckAuth, getShorthands)
ginServer.Handle("POST", "/api/inbox/getShorthand", model.CheckAuth, getShorthand)
ginServer.Handle("POST", "/api/inbox/removeShorthands", model.CheckAuth, model.CheckReadonly, removeShorthands)
ginServer.Handle("POST", "/api/inbox/getShorthands", model.CheckAuth, model.CheckAdminRole, getShorthands)
ginServer.Handle("POST", "/api/inbox/getShorthand", model.CheckAuth, model.CheckAdminRole, getShorthand)
ginServer.Handle("POST", "/api/inbox/removeShorthands", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeShorthands)
ginServer.Handle("POST", "/api/extension/copy", model.CheckAuth, model.CheckReadonly, extensionCopy)
ginServer.Handle("POST", "/api/extension/copy", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, extensionCopy)
ginServer.Handle("POST", "/api/clipboard/readFilePaths", model.CheckAuth, readFilePaths)
ginServer.Handle("POST", "/api/clipboard/readFilePaths", model.CheckAuth, model.CheckAdminRole, readFilePaths)
ginServer.Handle("POST", "/api/asset/uploadCloud", model.CheckAuth, model.CheckReadonly, uploadCloud)
ginServer.Handle("POST", "/api/asset/insertLocalAssets", model.CheckAuth, model.CheckReadonly, insertLocalAssets)
ginServer.Handle("POST", "/api/asset/uploadCloud", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uploadCloud)
ginServer.Handle("POST", "/api/asset/insertLocalAssets", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, insertLocalAssets)
ginServer.Handle("POST", "/api/asset/resolveAssetPath", model.CheckAuth, resolveAssetPath)
ginServer.Handle("POST", "/api/asset/upload", model.CheckAuth, model.CheckReadonly, model.Upload)
ginServer.Handle("POST", "/api/asset/setFileAnnotation", model.CheckAuth, model.CheckReadonly, setFileAnnotation)
ginServer.Handle("POST", "/api/asset/upload", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, model.Upload)
ginServer.Handle("POST", "/api/asset/setFileAnnotation", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setFileAnnotation)
ginServer.Handle("POST", "/api/asset/getFileAnnotation", model.CheckAuth, getFileAnnotation)
ginServer.Handle("POST", "/api/asset/getUnusedAssets", model.CheckAuth, getUnusedAssets)
ginServer.Handle("POST", "/api/asset/getMissingAssets", model.CheckAuth, getMissingAssets)
ginServer.Handle("POST", "/api/asset/removeUnusedAsset", model.CheckAuth, model.CheckReadonly, removeUnusedAsset)
ginServer.Handle("POST", "/api/asset/removeUnusedAssets", model.CheckAuth, model.CheckReadonly, removeUnusedAssets)
ginServer.Handle("POST", "/api/asset/removeUnusedAsset", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeUnusedAsset)
ginServer.Handle("POST", "/api/asset/removeUnusedAssets", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeUnusedAssets)
ginServer.Handle("POST", "/api/asset/getDocImageAssets", model.CheckAuth, getDocImageAssets)
ginServer.Handle("POST", "/api/asset/renameAsset", model.CheckAuth, model.CheckReadonly, renameAsset)
ginServer.Handle("POST", "/api/asset/getImageOCRText", model.CheckAuth, model.CheckReadonly, getImageOCRText)
ginServer.Handle("POST", "/api/asset/setImageOCRText", model.CheckAuth, model.CheckReadonly, setImageOCRText)
ginServer.Handle("POST", "/api/asset/fullReindexAssetContent", model.CheckAuth, model.CheckReadonly, fullReindexAssetContent)
ginServer.Handle("POST", "/api/asset/statAsset", model.CheckAuth, statAsset)
ginServer.Handle("POST", "/api/asset/renameAsset", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameAsset)
ginServer.Handle("POST", "/api/asset/getImageOCRText", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getImageOCRText)
ginServer.Handle("POST", "/api/asset/setImageOCRText", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setImageOCRText)
ginServer.Handle("POST", "/api/asset/fullReindexAssetContent", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, fullReindexAssetContent)
ginServer.Handle("POST", "/api/asset/statAsset", model.CheckAuth, model.CheckAdminRole, statAsset)
ginServer.Handle("POST", "/api/export/batchExportMd", model.CheckAuth, batchExportMd)
ginServer.Handle("POST", "/api/export/exportMd", model.CheckAuth, exportMd)
@ -286,7 +285,7 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, exportData)
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, exportDataInFolder)
ginServer.Handle("POST", "/api/export/exportTempContent", model.CheckAuth, exportTempContent)
ginServer.Handle("POST", "/api/export/export2Liandi", model.CheckAuth, export2Liandi)
ginServer.Handle("POST", "/api/export/export2Liandi", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, export2Liandi)
ginServer.Handle("POST", "/api/export/exportReStructuredText", model.CheckAuth, exportReStructuredText)
ginServer.Handle("POST", "/api/export/exportAsciiDoc", model.CheckAuth, exportAsciiDoc)
ginServer.Handle("POST", "/api/export/exportTextile", model.CheckAuth, exportTextile)
@ -298,150 +297,152 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/export/exportEPUB", model.CheckAuth, exportEPUB)
ginServer.Handle("POST", "/api/export/exportAttributeView", model.CheckAuth, exportAttributeView)
ginServer.Handle("POST", "/api/import/importStdMd", model.CheckAuth, model.CheckReadonly, importStdMd)
ginServer.Handle("POST", "/api/import/importData", model.CheckAuth, model.CheckReadonly, importData)
ginServer.Handle("POST", "/api/import/importSY", model.CheckAuth, model.CheckReadonly, importSY)
ginServer.Handle("POST", "/api/import/importStdMd", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importStdMd)
ginServer.Handle("POST", "/api/import/importData", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importData)
ginServer.Handle("POST", "/api/import/importSY", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importSY)
ginServer.Handle("POST", "/api/convert/pandoc", model.CheckAuth, model.CheckReadonly, pandoc)
ginServer.Handle("POST", "/api/convert/pandoc", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, pandoc)
ginServer.Handle("POST", "/api/template/render", model.CheckAuth, renderTemplate)
ginServer.Handle("POST", "/api/template/docSaveAsTemplate", model.CheckAuth, model.CheckReadonly, docSaveAsTemplate)
ginServer.Handle("POST", "/api/template/render", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renderTemplate)
ginServer.Handle("POST", "/api/template/docSaveAsTemplate", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, docSaveAsTemplate)
ginServer.Handle("POST", "/api/template/renderSprig", model.CheckAuth, renderSprig)
ginServer.Handle("POST", "/api/transactions", model.CheckAuth, model.CheckReadonly, performTransactions)
ginServer.Handle("POST", "/api/transactions", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, performTransactions)
ginServer.Handle("POST", "/api/setting/setAccount", model.CheckAuth, model.CheckReadonly, setAccount)
ginServer.Handle("POST", "/api/setting/setEditor", model.CheckAuth, model.CheckReadonly, setEditor)
ginServer.Handle("POST", "/api/setting/setExport", model.CheckAuth, model.CheckReadonly, setExport)
ginServer.Handle("POST", "/api/setting/setFiletree", model.CheckAuth, model.CheckReadonly, setFiletree)
ginServer.Handle("POST", "/api/setting/setSearch", model.CheckAuth, model.CheckReadonly, setSearch)
ginServer.Handle("POST", "/api/setting/setKeymap", model.CheckAuth, model.CheckReadonly, setKeymap)
ginServer.Handle("POST", "/api/setting/setAppearance", model.CheckAuth, model.CheckReadonly, setAppearance)
ginServer.Handle("POST", "/api/setting/getCloudUser", model.CheckAuth, getCloudUser)
ginServer.Handle("POST", "/api/setting/logoutCloudUser", model.CheckAuth, model.CheckReadonly, logoutCloudUser)
ginServer.Handle("POST", "/api/setting/login2faCloudUser", model.CheckAuth, model.CheckReadonly, login2faCloudUser)
ginServer.Handle("POST", "/api/setting/setEmoji", model.CheckAuth, model.CheckReadonly, setEmoji)
ginServer.Handle("POST", "/api/setting/setFlashcard", model.CheckAuth, model.CheckReadonly, setFlashcard)
ginServer.Handle("POST", "/api/setting/setAI", model.CheckAuth, model.CheckReadonly, setAI)
ginServer.Handle("POST", "/api/setting/setBazaar", model.CheckAuth, model.CheckReadonly, setBazaar)
ginServer.Handle("POST", "/api/setting/refreshVirtualBlockRef", model.CheckAuth, model.CheckReadonly, refreshVirtualBlockRef)
ginServer.Handle("POST", "/api/setting/addVirtualBlockRefInclude", model.CheckAuth, model.CheckReadonly, addVirtualBlockRefInclude)
ginServer.Handle("POST", "/api/setting/addVirtualBlockRefExclude", model.CheckAuth, model.CheckReadonly, addVirtualBlockRefExclude)
ginServer.Handle("POST", "/api/setting/setSnippet", model.CheckAuth, model.CheckReadonly, setConfSnippet)
ginServer.Handle("POST", "/api/setting/setEditorReadOnly", model.CheckAuth, model.CheckReadonly, setEditorReadOnly)
ginServer.Handle("POST", "/api/setting/setAccount", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAccount)
ginServer.Handle("POST", "/api/setting/setEditor", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setEditor)
ginServer.Handle("POST", "/api/setting/setExport", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setExport)
ginServer.Handle("POST", "/api/setting/setFiletree", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setFiletree)
ginServer.Handle("POST", "/api/setting/setSearch", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSearch)
ginServer.Handle("POST", "/api/setting/setKeymap", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setKeymap)
ginServer.Handle("POST", "/api/setting/setAppearance", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAppearance)
ginServer.Handle("POST", "/api/setting/getCloudUser", model.CheckAuth, model.CheckAdminRole, getCloudUser)
ginServer.Handle("POST", "/api/setting/logoutCloudUser", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, logoutCloudUser)
ginServer.Handle("POST", "/api/setting/login2faCloudUser", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, login2faCloudUser)
ginServer.Handle("POST", "/api/setting/setEmoji", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setEmoji)
ginServer.Handle("POST", "/api/setting/setFlashcard", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setFlashcard)
ginServer.Handle("POST", "/api/setting/setAI", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAI)
ginServer.Handle("POST", "/api/setting/setBazaar", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setBazaar)
ginServer.Handle("POST", "/api/setting/setPublish", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setPublish)
ginServer.Handle("POST", "/api/setting/getPublish", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getPublish)
ginServer.Handle("POST", "/api/setting/refreshVirtualBlockRef", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, refreshVirtualBlockRef)
ginServer.Handle("POST", "/api/setting/addVirtualBlockRefInclude", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addVirtualBlockRefInclude)
ginServer.Handle("POST", "/api/setting/addVirtualBlockRefExclude", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addVirtualBlockRefExclude)
ginServer.Handle("POST", "/api/setting/setSnippet", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setConfSnippet)
ginServer.Handle("POST", "/api/setting/setEditorReadOnly", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setEditorReadOnly)
ginServer.Handle("POST", "/api/graph/resetGraph", model.CheckAuth, model.CheckReadonly, resetGraph)
ginServer.Handle("POST", "/api/graph/resetLocalGraph", model.CheckAuth, model.CheckReadonly, resetLocalGraph)
ginServer.Handle("POST", "/api/graph/resetGraph", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetGraph)
ginServer.Handle("POST", "/api/graph/resetLocalGraph", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetLocalGraph)
ginServer.Handle("POST", "/api/graph/getGraph", model.CheckAuth, getGraph)
ginServer.Handle("POST", "/api/graph/getLocalGraph", model.CheckAuth, getLocalGraph)
ginServer.Handle("POST", "/api/bazaar/getBazaarPlugin", model.CheckAuth, getBazaarPlugin)
ginServer.Handle("POST", "/api/bazaar/getInstalledPlugin", model.CheckAuth, getInstalledPlugin)
ginServer.Handle("POST", "/api/bazaar/installBazaarPlugin", model.CheckAuth, model.CheckReadonly, installBazaarPlugin)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarPlugin", model.CheckAuth, model.CheckReadonly, uninstallBazaarPlugin)
ginServer.Handle("POST", "/api/bazaar/installBazaarPlugin", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, installBazaarPlugin)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarPlugin", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uninstallBazaarPlugin)
ginServer.Handle("POST", "/api/bazaar/getBazaarWidget", model.CheckAuth, getBazaarWidget)
ginServer.Handle("POST", "/api/bazaar/getInstalledWidget", model.CheckAuth, getInstalledWidget)
ginServer.Handle("POST", "/api/bazaar/installBazaarWidget", model.CheckAuth, model.CheckReadonly, installBazaarWidget)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarWidget", model.CheckAuth, model.CheckReadonly, uninstallBazaarWidget)
ginServer.Handle("POST", "/api/bazaar/installBazaarWidget", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, installBazaarWidget)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarWidget", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uninstallBazaarWidget)
ginServer.Handle("POST", "/api/bazaar/getBazaarIcon", model.CheckAuth, getBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/getInstalledIcon", model.CheckAuth, getInstalledIcon)
ginServer.Handle("POST", "/api/bazaar/installBazaarIcon", model.CheckAuth, model.CheckReadonly, installBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarIcon", model.CheckAuth, model.CheckReadonly, uninstallBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/installBazaarIcon", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, installBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarIcon", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uninstallBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/getBazaarTemplate", model.CheckAuth, getBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/getInstalledTemplate", model.CheckAuth, getInstalledTemplate)
ginServer.Handle("POST", "/api/bazaar/installBazaarTemplate", model.CheckAuth, model.CheckReadonly, installBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTemplate", model.CheckAuth, model.CheckReadonly, uninstallBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/installBazaarTemplate", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, installBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTemplate", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uninstallBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/getBazaarTheme", model.CheckAuth, getBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/getInstalledTheme", model.CheckAuth, getInstalledTheme)
ginServer.Handle("POST", "/api/bazaar/installBazaarTheme", model.CheckAuth, model.CheckReadonly, installBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTheme", model.CheckAuth, model.CheckReadonly, uninstallBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/installBazaarTheme", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, installBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTheme", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uninstallBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/getBazaarPackageREAME", model.CheckAuth, getBazaarPackageREAME)
ginServer.Handle("POST", "/api/bazaar/getUpdatedPackage", model.CheckAuth, getUpdatedPackage)
ginServer.Handle("POST", "/api/bazaar/batchUpdatePackage", model.CheckAuth, batchUpdatePackage)
ginServer.Handle("POST", "/api/bazaar/batchUpdatePackage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchUpdatePackage)
ginServer.Handle("POST", "/api/repo/initRepoKey", model.CheckAuth, model.CheckReadonly, initRepoKey)
ginServer.Handle("POST", "/api/repo/initRepoKeyFromPassphrase", model.CheckAuth, model.CheckReadonly, initRepoKeyFromPassphrase)
ginServer.Handle("POST", "/api/repo/resetRepo", model.CheckAuth, model.CheckReadonly, resetRepo)
ginServer.Handle("POST", "/api/repo/purgeRepo", model.CheckAuth, model.CheckReadonly, purgeRepo)
ginServer.Handle("POST", "/api/repo/purgeCloudRepo", model.CheckAuth, model.CheckReadonly, purgeCloudRepo)
ginServer.Handle("POST", "/api/repo/importRepoKey", model.CheckAuth, model.CheckReadonly, importRepoKey)
ginServer.Handle("POST", "/api/repo/createSnapshot", model.CheckAuth, model.CheckReadonly, createSnapshot)
ginServer.Handle("POST", "/api/repo/tagSnapshot", model.CheckAuth, model.CheckReadonly, tagSnapshot)
ginServer.Handle("POST", "/api/repo/checkoutRepo", model.CheckAuth, model.CheckReadonly, checkoutRepo)
ginServer.Handle("POST", "/api/repo/getRepoSnapshots", model.CheckAuth, getRepoSnapshots)
ginServer.Handle("POST", "/api/repo/getRepoTagSnapshots", model.CheckAuth, getRepoTagSnapshots)
ginServer.Handle("POST", "/api/repo/removeRepoTagSnapshot", model.CheckAuth, model.CheckReadonly, removeRepoTagSnapshot)
ginServer.Handle("POST", "/api/repo/getCloudRepoTagSnapshots", model.CheckAuth, getCloudRepoTagSnapshots)
ginServer.Handle("POST", "/api/repo/getCloudRepoSnapshots", model.CheckAuth, getCloudRepoSnapshots)
ginServer.Handle("POST", "/api/repo/removeCloudRepoTagSnapshot", model.CheckAuth, model.CheckReadonly, removeCloudRepoTagSnapshot)
ginServer.Handle("POST", "/api/repo/uploadCloudSnapshot", model.CheckAuth, model.CheckReadonly, uploadCloudSnapshot)
ginServer.Handle("POST", "/api/repo/downloadCloudSnapshot", model.CheckAuth, model.CheckReadonly, downloadCloudSnapshot)
ginServer.Handle("POST", "/api/repo/diffRepoSnapshots", model.CheckAuth, diffRepoSnapshots)
ginServer.Handle("POST", "/api/repo/openRepoSnapshotDoc", model.CheckAuth, openRepoSnapshotDoc)
ginServer.Handle("POST", "/api/repo/getRepoFile", model.CheckAuth, getRepoFile)
ginServer.Handle("POST", "/api/repo/initRepoKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, initRepoKey)
ginServer.Handle("POST", "/api/repo/initRepoKeyFromPassphrase", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, initRepoKeyFromPassphrase)
ginServer.Handle("POST", "/api/repo/resetRepo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetRepo)
ginServer.Handle("POST", "/api/repo/purgeRepo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, purgeRepo)
ginServer.Handle("POST", "/api/repo/purgeCloudRepo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, purgeCloudRepo)
ginServer.Handle("POST", "/api/repo/importRepoKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, importRepoKey)
ginServer.Handle("POST", "/api/repo/createSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createSnapshot)
ginServer.Handle("POST", "/api/repo/tagSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, tagSnapshot)
ginServer.Handle("POST", "/api/repo/checkoutRepo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, checkoutRepo)
ginServer.Handle("POST", "/api/repo/getRepoSnapshots", model.CheckAuth, model.CheckAdminRole, getRepoSnapshots)
ginServer.Handle("POST", "/api/repo/getRepoTagSnapshots", model.CheckAuth, model.CheckAdminRole, getRepoTagSnapshots)
ginServer.Handle("POST", "/api/repo/removeRepoTagSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeRepoTagSnapshot)
ginServer.Handle("POST", "/api/repo/getCloudRepoTagSnapshots", model.CheckAuth, model.CheckAdminRole, getCloudRepoTagSnapshots)
ginServer.Handle("POST", "/api/repo/getCloudRepoSnapshots", model.CheckAuth, model.CheckAdminRole, getCloudRepoSnapshots)
ginServer.Handle("POST", "/api/repo/removeCloudRepoTagSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeCloudRepoTagSnapshot)
ginServer.Handle("POST", "/api/repo/uploadCloudSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, uploadCloudSnapshot)
ginServer.Handle("POST", "/api/repo/downloadCloudSnapshot", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, downloadCloudSnapshot)
ginServer.Handle("POST", "/api/repo/diffRepoSnapshots", model.CheckAuth, model.CheckAdminRole, diffRepoSnapshots)
ginServer.Handle("POST", "/api/repo/openRepoSnapshotDoc", model.CheckAuth, model.CheckAdminRole, openRepoSnapshotDoc)
ginServer.Handle("POST", "/api/repo/getRepoFile", model.CheckAuth, model.CheckAdminRole, getRepoFile)
ginServer.Handle("POST", "/api/riff/createRiffDeck", model.CheckAuth, model.CheckReadonly, createRiffDeck)
ginServer.Handle("POST", "/api/riff/renameRiffDeck", model.CheckAuth, model.CheckReadonly, renameRiffDeck)
ginServer.Handle("POST", "/api/riff/removeRiffDeck", model.CheckAuth, model.CheckReadonly, removeRiffDeck)
ginServer.Handle("POST", "/api/riff/getRiffDecks", model.CheckAuth, getRiffDecks)
ginServer.Handle("POST", "/api/riff/addRiffCards", model.CheckAuth, model.CheckReadonly, addRiffCards)
ginServer.Handle("POST", "/api/riff/removeRiffCards", model.CheckAuth, model.CheckReadonly, removeRiffCards)
ginServer.Handle("POST", "/api/riff/getRiffDueCards", model.CheckAuth, getRiffDueCards)
ginServer.Handle("POST", "/api/riff/getTreeRiffDueCards", model.CheckAuth, getTreeRiffDueCards)
ginServer.Handle("POST", "/api/riff/getNotebookRiffDueCards", model.CheckAuth, getNotebookRiffDueCards)
ginServer.Handle("POST", "/api/riff/reviewRiffCard", model.CheckAuth, model.CheckReadonly, reviewRiffCard)
ginServer.Handle("POST", "/api/riff/skipReviewRiffCard", model.CheckAuth, model.CheckReadonly, skipReviewRiffCard)
ginServer.Handle("POST", "/api/riff/getRiffCards", model.CheckAuth, getRiffCards)
ginServer.Handle("POST", "/api/riff/getTreeRiffCards", model.CheckAuth, getTreeRiffCards)
ginServer.Handle("POST", "/api/riff/getNotebookRiffCards", model.CheckAuth, getNotebookRiffCards)
ginServer.Handle("POST", "/api/riff/resetRiffCards", model.CheckAuth, model.CheckReadonly, resetRiffCards)
ginServer.Handle("POST", "/api/riff/batchSetRiffCardsDueTime", model.CheckAuth, model.CheckReadonly, batchSetRiffCardsDueTime)
ginServer.Handle("POST", "/api/riff/getRiffCardsByBlockIDs", model.CheckAuth, model.CheckReadonly, getRiffCardsByBlockIDs)
ginServer.Handle("POST", "/api/riff/createRiffDeck", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, createRiffDeck)
ginServer.Handle("POST", "/api/riff/renameRiffDeck", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameRiffDeck)
ginServer.Handle("POST", "/api/riff/removeRiffDeck", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeRiffDeck)
ginServer.Handle("POST", "/api/riff/getRiffDecks", model.CheckAuth, model.CheckAdminRole, getRiffDecks)
ginServer.Handle("POST", "/api/riff/addRiffCards", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addRiffCards)
ginServer.Handle("POST", "/api/riff/removeRiffCards", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeRiffCards)
ginServer.Handle("POST", "/api/riff/getRiffDueCards", model.CheckAuth, model.CheckAdminRole, getRiffDueCards)
ginServer.Handle("POST", "/api/riff/getTreeRiffDueCards", model.CheckAuth, model.CheckAdminRole, getTreeRiffDueCards)
ginServer.Handle("POST", "/api/riff/getNotebookRiffDueCards", model.CheckAuth, model.CheckAdminRole, getNotebookRiffDueCards)
ginServer.Handle("POST", "/api/riff/reviewRiffCard", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reviewRiffCard)
ginServer.Handle("POST", "/api/riff/skipReviewRiffCard", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, skipReviewRiffCard)
ginServer.Handle("POST", "/api/riff/getRiffCards", model.CheckAuth, model.CheckAdminRole, getRiffCards)
ginServer.Handle("POST", "/api/riff/getTreeRiffCards", model.CheckAuth, model.CheckAdminRole, getTreeRiffCards)
ginServer.Handle("POST", "/api/riff/getNotebookRiffCards", model.CheckAuth, model.CheckAdminRole, getNotebookRiffCards)
ginServer.Handle("POST", "/api/riff/resetRiffCards", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, resetRiffCards)
ginServer.Handle("POST", "/api/riff/batchSetRiffCardsDueTime", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchSetRiffCardsDueTime)
ginServer.Handle("POST", "/api/riff/getRiffCardsByBlockIDs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getRiffCardsByBlockIDs)
ginServer.Handle("POST", "/api/notification/pushMsg", model.CheckAuth, pushMsg)
ginServer.Handle("POST", "/api/notification/pushErrMsg", model.CheckAuth, pushErrMsg)
ginServer.Handle("POST", "/api/notification/pushMsg", model.CheckAuth, model.CheckAdminRole, pushMsg)
ginServer.Handle("POST", "/api/notification/pushErrMsg", model.CheckAuth, model.CheckAdminRole, pushErrMsg)
ginServer.Handle("POST", "/api/snippet/getSnippet", model.CheckAuth, getSnippet)
ginServer.Handle("POST", "/api/snippet/setSnippet", model.CheckAuth, model.CheckReadonly, setSnippet)
ginServer.Handle("POST", "/api/snippet/removeSnippet", model.CheckAuth, model.CheckReadonly, removeSnippet)
ginServer.Handle("POST", "/api/snippet/setSnippet", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setSnippet)
ginServer.Handle("POST", "/api/snippet/removeSnippet", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeSnippet)
ginServer.Handle("POST", "/api/av/renderAttributeView", model.CheckAuth, renderAttributeView)
ginServer.Handle("POST", "/api/av/renderHistoryAttributeView", model.CheckAuth, renderHistoryAttributeView)
ginServer.Handle("POST", "/api/av/renderSnapshotAttributeView", model.CheckAuth, renderSnapshotAttributeView)
ginServer.Handle("POST", "/api/av/renderHistoryAttributeView", model.CheckAuth, model.CheckAdminRole, renderHistoryAttributeView)
ginServer.Handle("POST", "/api/av/renderSnapshotAttributeView", model.CheckAuth, model.CheckAdminRole, renderSnapshotAttributeView)
ginServer.Handle("POST", "/api/av/getAttributeViewKeys", model.CheckAuth, getAttributeViewKeys)
ginServer.Handle("POST", "/api/av/setAttributeViewBlockAttr", model.CheckAuth, model.CheckReadonly, setAttributeViewBlockAttr)
ginServer.Handle("POST", "/api/av/setAttributeViewBlockAttr", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAttributeViewBlockAttr)
ginServer.Handle("POST", "/api/av/searchAttributeView", model.CheckAuth, model.CheckReadonly, searchAttributeView)
ginServer.Handle("POST", "/api/av/getAttributeView", model.CheckAuth, model.CheckReadonly, getAttributeView)
ginServer.Handle("POST", "/api/av/searchAttributeViewRelationKey", model.CheckAuth, model.CheckReadonly, searchAttributeViewRelationKey)
ginServer.Handle("POST", "/api/av/searchAttributeViewNonRelationKey", model.CheckAuth, model.CheckReadonly, searchAttributeViewNonRelationKey)
ginServer.Handle("POST", "/api/av/getAttributeViewFilterSort", model.CheckAuth, model.CheckReadonly, getAttributeViewFilterSort)
ginServer.Handle("POST", "/api/av/addAttributeViewKey", model.CheckAuth, model.CheckReadonly, addAttributeViewKey)
ginServer.Handle("POST", "/api/av/removeAttributeViewKey", model.CheckAuth, model.CheckReadonly, removeAttributeViewKey)
ginServer.Handle("POST", "/api/av/sortAttributeViewViewKey", model.CheckAuth, model.CheckReadonly, sortAttributeViewViewKey)
ginServer.Handle("POST", "/api/av/sortAttributeViewKey", model.CheckAuth, model.CheckReadonly, sortAttributeViewKey)
ginServer.Handle("POST", "/api/av/addAttributeViewBlocks", model.CheckAuth, model.CheckReadonly, addAttributeViewBlocks)
ginServer.Handle("POST", "/api/av/removeAttributeViewBlocks", model.CheckAuth, model.CheckReadonly, removeAttributeViewBlocks)
ginServer.Handle("POST", "/api/av/getAttributeViewPrimaryKeyValues", model.CheckAuth, model.CheckReadonly, getAttributeViewPrimaryKeyValues)
ginServer.Handle("POST", "/api/av/setDatabaseBlockView", model.CheckAuth, model.CheckReadonly, setDatabaseBlockView)
ginServer.Handle("POST", "/api/av/getMirrorDatabaseBlocks", model.CheckAuth, model.CheckReadonly, getMirrorDatabaseBlocks)
ginServer.Handle("POST", "/api/av/getAttributeViewKeysByAvID", model.CheckAuth, model.CheckReadonly, getAttributeViewKeysByAvID)
ginServer.Handle("POST", "/api/av/duplicateAttributeViewBlock", model.CheckAuth, model.CheckReadonly, duplicateAttributeViewBlock)
ginServer.Handle("POST", "/api/av/appendAttributeViewDetachedBlocksWithValues", model.CheckAuth, model.CheckReadonly, appendAttributeViewDetachedBlocksWithValues)
ginServer.Handle("POST", "/api/av/searchAttributeViewRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewRelationKey)
ginServer.Handle("POST", "/api/av/searchAttributeViewNonRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewNonRelationKey)
ginServer.Handle("POST", "/api/av/getAttributeViewFilterSort", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getAttributeViewFilterSort)
ginServer.Handle("POST", "/api/av/addAttributeViewKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addAttributeViewKey)
ginServer.Handle("POST", "/api/av/removeAttributeViewKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeAttributeViewKey)
ginServer.Handle("POST", "/api/av/sortAttributeViewViewKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, sortAttributeViewViewKey)
ginServer.Handle("POST", "/api/av/sortAttributeViewKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, sortAttributeViewKey)
ginServer.Handle("POST", "/api/av/addAttributeViewBlocks", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, addAttributeViewBlocks)
ginServer.Handle("POST", "/api/av/removeAttributeViewBlocks", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeAttributeViewBlocks)
ginServer.Handle("POST", "/api/av/getAttributeViewPrimaryKeyValues", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getAttributeViewPrimaryKeyValues)
ginServer.Handle("POST", "/api/av/setDatabaseBlockView", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setDatabaseBlockView)
ginServer.Handle("POST", "/api/av/getMirrorDatabaseBlocks", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getMirrorDatabaseBlocks)
ginServer.Handle("POST", "/api/av/getAttributeViewKeysByAvID", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getAttributeViewKeysByAvID)
ginServer.Handle("POST", "/api/av/duplicateAttributeViewBlock", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, duplicateAttributeViewBlock)
ginServer.Handle("POST", "/api/av/appendAttributeViewDetachedBlocksWithValues", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, appendAttributeViewDetachedBlocksWithValues)
ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, chatGPT)
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, chatGPTWithAction)
ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckAdminRole, chatGPT)
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckAdminRole, chatGPTWithAction)
ginServer.Handle("POST", "/api/petal/loadPetals", model.CheckAuth, loadPetals)
ginServer.Handle("POST", "/api/petal/setPetalEnabled", model.CheckAuth, model.CheckReadonly, setPetalEnabled)
ginServer.Handle("POST", "/api/petal/setPetalEnabled", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setPetalEnabled)
ginServer.Any("/api/network/echo", model.CheckAuth, echo)
ginServer.Handle("POST", "/api/network/forwardProxy", model.CheckAuth, forwardProxy)
ginServer.Any("/api/network/echo", model.CheckAuth, model.CheckAdminRole, echo)
ginServer.Handle("POST", "/api/network/forwardProxy", model.CheckAuth, model.CheckAdminRole, forwardProxy)
ginServer.Handle("GET", "/ws/broadcast", model.CheckAuth, broadcast)
ginServer.Handle("POST", "/api/broadcast/postMessage", model.CheckAuth, postMessage)
ginServer.Handle("POST", "/api/broadcast/getChannels", model.CheckAuth, getChannels)
ginServer.Handle("POST", "/api/broadcast/getChannelInfo", model.CheckAuth, getChannelInfo)
ginServer.Handle("GET", "/ws/broadcast", model.CheckAuth, model.CheckAdminRole, broadcast)
ginServer.Handle("POST", "/api/broadcast/postMessage", model.CheckAuth, model.CheckAdminRole, postMessage)
ginServer.Handle("POST", "/api/broadcast/getChannels", model.CheckAuth, model.CheckAdminRole, getChannels)
ginServer.Handle("POST", "/api/broadcast/getChannelInfo", model.CheckAuth, model.CheckAdminRole, getChannelInfo)
ginServer.Handle("POST", "/api/archive/zip", model.CheckAuth, model.CheckReadonly, zip)
ginServer.Handle("POST", "/api/archive/unzip", model.CheckAuth, model.CheckReadonly, unzip)
ginServer.Handle("POST", "/api/archive/zip", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, zip)
ginServer.Handle("POST", "/api/archive/unzip", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, unzip)
}

View file

@ -25,6 +25,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/siyuan-note/siyuan/kernel/conf"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/server/proxy"
"github.com/siyuan-note/siyuan/kernel/sql"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -533,6 +534,58 @@ func setAppearance(c *gin.Context) {
ret.Data = model.Conf.Appearance
}
func setPublish(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok {
return
}
param, err := gulu.JSON.MarshalJSON(arg)
if nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
}
publish := &conf.Publish{}
if err = gulu.JSON.UnmarshalJSON(param, publish); nil != err {
ret.Code = -1
ret.Msg = err.Error()
return
}
model.Conf.Publish = publish
model.Conf.Save()
if port, err := proxy.InitPublishService(); err != nil {
ret.Code = -1
ret.Msg = err.Error()
} else {
ret.Data = map[string]any{
"port": port,
"publish": model.Conf.Publish,
}
}
}
func getPublish(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
if port, err := proxy.InitPublishService(); err != nil {
ret.Code = -1
ret.Msg = err.Error()
} else {
ret.Data = map[string]any{
"port": port,
"publish": model.Conf.Publish,
}
}
}
func getCloudUser(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -17,44 +17,17 @@
package api
import (
"mime"
"net/http"
"path/filepath"
"strings"
"github.com/88250/gulu"
"github.com/88250/lute/ast"
"github.com/gin-gonic/gin"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/conf"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
)
func serveSnippets(c *gin.Context) {
filePath := strings.TrimPrefix(c.Request.URL.Path, "/snippets/")
ext := filepath.Ext(filePath)
name := strings.TrimSuffix(filePath, ext)
confSnippets, err := model.LoadSnippets()
if nil != err {
logging.LogErrorf("load snippets failed: %s", err)
c.Status(404)
return
}
for _, s := range confSnippets {
if s.Name == name && ("" != ext && s.Type == ext[1:]) {
c.Header("Content-Type", mime.TypeByExtension(ext))
c.String(http.StatusOK, s.Content)
return
}
}
// 没有在配置文件中命中时在文件系统上查找
filePath = filepath.Join(util.SnippetsPath, filePath)
c.File(filePath)
}
func getSnippet(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -17,7 +17,6 @@
package api
import (
"github.com/88250/lute"
"net/http"
"os"
"path/filepath"
@ -25,6 +24,8 @@ import (
"sync"
"time"
"github.com/88250/lute"
"github.com/88250/gulu"
"github.com/gin-gonic/gin"
"github.com/siyuan-note/logging"
@ -218,6 +219,17 @@ func getConf(c *gin.Context) {
maskedConf.Sync.Stat = model.Conf.Language(53)
}
// REF: https://github.com/siyuan-note/siyuan/issues/11364
role := model.GetGinContextRole(c)
if model.IsReadOnlyRole(role) {
maskedConf.ReadOnly = true
}
if !model.IsValidRole(role, []model.Role{
model.RoleAdministrator,
}) {
model.HideConfSecret(maskedConf)
}
ret.Data = map[string]interface{}{
"conf": maskedConf,
"start": !util.IsUILoaded,

45
kernel/conf/publish.go Normal file
View file

@ -0,0 +1,45 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package conf
type Publish struct {
Enable bool `json:"enable"` // 是否启用发布服务
Port uint16 `json:"port"` // 发布服务端口
Auth *BasicAuth `json:"auth"` // Basic 认证
}
type BasicAuth struct {
Enable bool `json:"enable"` // 是否启用基础认证
Accounts []*BasicAuthAccount `json:"accounts"` // 账户列表
}
type BasicAuthAccount struct {
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
Memo string `json:"memo"` // 备注
}
func NewPublish() *Publish {
return &Publish{
Enable: false,
Port: 6808,
Auth: &BasicAuth{
Enable: true,
Accounts: []*BasicAuthAccount{},
},
}
}

View file

@ -33,6 +33,7 @@ require (
github.com/go-ole/go-ole v1.3.0
github.com/goccy/go-json v0.10.3
github.com/gofrs/flock v0.8.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/gorilla/css v1.0.1
github.com/gorilla/websocket v1.5.1
github.com/imroc/req/v3 v3.43.7

View file

@ -154,6 +154,8 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=

133
kernel/model/auth.go Normal file
View file

@ -0,0 +1,133 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package model
import (
"crypto/rand"
"net/http"
"github.com/golang-jwt/jwt/v5"
"github.com/siyuan-note/logging"
)
type Account struct {
Username string
Password string
Token string
}
type AccountsMap map[string]*Account
type ClaimsKeyType string
const (
XAuthTokenKey = "X-Auth-Token"
ClaimsContextKey = "claims"
iss = "siyuan-publish-reverse-proxy-server"
sub = "publish"
aud = "siyuan-kernel"
ClaimsKeyRole string = "role"
)
var (
accountsMap = AccountsMap{}
key = make([]byte, 32)
)
func GetBasicAuthAccount(username string) *Account {
return accountsMap[username]
}
func InitAccounts() {
accountsMap = AccountsMap{
"": &Account{}, // 匿名用户
}
for _, account := range Conf.Publish.Auth.Accounts {
accountsMap[account.Username] = &Account{
Username: account.Username,
Password: account.Password,
}
}
InitJWT()
}
func InitJWT() {
if _, err := rand.Read(key); err != nil {
logging.LogErrorf("generate JWT signing key failed: %s", err)
return
}
for username, account := range accountsMap {
// REF: https://golang-jwt.github.io/jwt/usage/create/
t := jwt.NewWithClaims(
jwt.SigningMethodHS256,
jwt.MapClaims{
"iss": iss,
"sub": sub,
"aud": aud,
"jti": username,
ClaimsKeyRole: RoleReader,
},
)
if token, err := t.SignedString(key); err != nil {
logging.LogErrorf("JWT signature failed: %s", err)
return
} else {
account.Token = token
}
}
}
func ParseJWT(tokenString string) (*jwt.Token, error) {
// REF: https://golang-jwt.github.io/jwt/usage/parse/
return jwt.Parse(
tokenString,
func(token *jwt.Token) (interface{}, error) {
return key, nil
},
jwt.WithIssuer(iss),
jwt.WithSubject(sub),
jwt.WithAudience(aud),
)
}
func ParseXAuthToken(r *http.Request) *jwt.Token {
tokenString := r.Header.Get(XAuthTokenKey)
if tokenString != "" {
if token, err := ParseJWT(tokenString); err != nil {
logging.LogErrorf("JWT parse failed: %s", err)
} else {
return token
}
}
return nil
}
func GetTokenClaims(token *jwt.Token) jwt.MapClaims {
return token.Claims.(jwt.MapClaims)
}
func GetClaimRole(claims jwt.MapClaims) Role {
if role := claims[ClaimsKeyRole]; role != nil {
return Role(role.(float64))
}
return RoleVisitor
}

View file

@ -76,6 +76,7 @@ type AppConf struct {
Stat *conf.Stat `json:"stat"` // 统计
Api *conf.API `json:"api"` // API
Repo *conf.Repo `json:"repo"` // 数据仓库
Publish *conf.Publish `json:"publish"` // 发布服务
OpenHelp bool `json:"openHelp"` // 启动后是否需要打开用户指南
ShowChangelog bool `json:"showChangelog"` // 是否显示版本更新日志
CloudRegion int `json:"cloudRegion"` // 云端区域0中国大陆1北美
@ -357,6 +358,10 @@ func InitConf() {
Conf.Bazaar = conf.NewBazaar()
}
if nil == Conf.Publish {
Conf.Publish = conf.NewPublish()
}
if nil == Conf.Repo {
Conf.Repo = conf.NewRepo()
}
@ -894,6 +899,24 @@ func GetMaskedConf() (ret *AppConf, err error) {
return
}
// REF: https://github.com/siyuan-note/siyuan/issues/11364
// HideConfSecret 隐藏设置中的秘密信息
func HideConfSecret(c *AppConf) {
c.AI = &conf.AI{}
c.Api = &conf.API{}
c.Flashcard = &conf.Flashcard{}
c.LocalIPs = []string{}
c.Publish = &conf.Publish{}
c.Repo = &conf.Repo{}
c.Sync = &conf.Sync{}
c.System.AppDir = ""
c.System.ConfDir = ""
c.System.DataDir = ""
c.System.HomeDir = ""
c.System.Name = ""
c.System.NetworkProxy = &conf.NetworkProxy{}
}
func clearPortJSON() {
pid := fmt.Sprintf("%d", os.Getpid())
portJSON := filepath.Join(util.HomeDir, ".config", "siyuan", "port.json")

56
kernel/model/role.go Normal file
View file

@ -0,0 +1,56 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package model
import "github.com/gin-gonic/gin"
type Role uint
const (
RoleContextKey = "role"
)
const (
RoleAdministrator Role = iota // 管理员
RoleEditor // 编辑者
RoleReader // 读者
RoleVisitor // 匿名访问者
)
func IsValidRole(role Role, roles []Role) bool {
for _, role_ := range roles {
if role == role_ {
return true
}
}
return false
}
func IsReadOnlyRole(role Role) bool {
return IsValidRole(role, []Role{
RoleReader,
RoleVisitor,
})
}
func GetGinContextRole(c *gin.Context) Role {
if role, exists := c.Get(RoleContextKey); exists {
return role.(Role)
} else {
return RoleVisitor
}
}

View file

@ -164,6 +164,16 @@ func CheckReadonly(c *gin.Context) {
}
func CheckAuth(c *gin.Context) {
// 已通过 JWT 认证
if role := GetGinContextRole(c); IsValidRole(role, []Role{
RoleAdministrator,
RoleEditor,
RoleReader,
}) {
c.Next()
return
}
//logging.LogInfof("check auth for [%s]", c.Request.RequestURI)
localhost := util.IsLocalHost(c.Request.RemoteAddr)
@ -171,6 +181,7 @@ func CheckAuth(c *gin.Context) {
if "" == Conf.AccessAuthCode {
// Skip the empty access authorization code check https://github.com/siyuan-note/siyuan/issues/9709
if util.SiyuanAccessAuthCodeBypass {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -190,6 +201,7 @@ func CheckAuth(c *gin.Context) {
return
}
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -206,19 +218,23 @@ func CheckAuth(c *gin.Context) {
// 放过来自本机的某些请求
if localhost {
if strings.HasPrefix(c.Request.RequestURI, "/assets/") {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
if strings.HasPrefix(c.Request.RequestURI, "/api/system/exit") {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
if strings.HasPrefix(c.Request.RequestURI, "/api/system/getNetwork") {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
if strings.HasPrefix(c.Request.RequestURI, "/api/sync/performSync") {
if util.ContainerIOS == util.Container || util.ContainerAndroid == util.Container {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -229,6 +245,7 @@ func CheckAuth(c *gin.Context) {
session := util.GetSession(c)
workspaceSession := util.GetWorkspaceSession(session)
if workspaceSession.AccessAuthCode == Conf.AccessAuthCode {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -248,6 +265,7 @@ func CheckAuth(c *gin.Context) {
if "" != token {
if Conf.Api.Token == token {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -261,6 +279,7 @@ func CheckAuth(c *gin.Context) {
// 通过 API token (query-params: token)
if token := c.Query("token"); "" != token {
if Conf.Api.Token == token {
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
return
}
@ -300,9 +319,43 @@ func CheckAuth(c *gin.Context) {
return
}
c.Set(RoleContextKey, RoleAdministrator)
c.Next()
}
func CheckAdminRole(c *gin.Context) {
if IsValidRole(GetGinContextRole(c), []Role{
RoleAdministrator,
}) {
c.Next()
} else {
c.AbortWithStatus(http.StatusForbidden)
}
}
func CheckEditRole(c *gin.Context) {
if IsValidRole(GetGinContextRole(c), []Role{
RoleAdministrator,
RoleEditor,
}) {
c.Next()
} else {
c.AbortWithStatus(http.StatusForbidden)
}
}
func CheckReadRole(c *gin.Context) {
if IsValidRole(GetGinContextRole(c), []Role{
RoleAdministrator,
RoleEditor,
RoleReader,
}) {
c.Next()
} else {
c.AbortWithStatus(http.StatusForbidden)
}
}
var timingAPIs = map[string]int{
"/api/search/fullTextSearchBlock": 200, // Monitor the search performance and suggest solutions https://github.com/siyuan-note/siyuan/issues/7873
}

View file

@ -18,7 +18,6 @@ package server
import (
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
@ -65,7 +64,7 @@ func killRunningKernel() {
}
func killByPort(port string) {
if !isPortOpen(port) {
if !util.IsPortOpen(port) {
return
}
@ -87,19 +86,6 @@ func killByPort(port string) {
logging.LogInfof("killed process [name=%s, pid=%s]", name, pid)
}
func isPortOpen(port string) bool {
timeout := time.Second
conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", port), timeout)
if nil != err {
return false
}
if nil != conn {
conn.Close()
return true
}
return false
}
func kill(pid string) {
var killCmd *exec.Cmd
if gulu.OS.IsWindows() {

View file

@ -0,0 +1,41 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package proxy
import (
"net/http"
"net/http/httputil"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
)
func InitFixedPortService(host string) {
if util.FixedPort != util.ServerPort {
if util.IsPortOpen(util.FixedPort) {
return
}
// 启动一个固定 6806 端口的反向代理服务器,这样浏览器扩展才能直接使用 127.0.0.1:6806不用配置端口
proxy := httputil.NewSingleHostReverseProxy(util.ServerURL)
logging.LogInfof("fixed port service [%s:%s] is running", host, util.FixedPort)
if proxyErr := http.ListenAndServe(host+":"+util.FixedPort, proxy); nil != proxyErr {
logging.LogWarnf("boot fixed port service [%s] failed: %s", util.ServerURL, proxyErr)
}
logging.LogInfof("fixed port service [%s:%s] is stopped", host, util.FixedPort)
}
}

View file

@ -0,0 +1,161 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package proxy
import (
"fmt"
"net"
"net/http"
"net/http/httputil"
"strconv"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
)
type PublishServiceTransport struct{}
var (
Host = "0.0.0.0"
Port = "0"
listener net.Listener
transport = PublishServiceTransport{}
proxy = &httputil.ReverseProxy{
Rewrite: rewrite,
Transport: transport,
}
)
func InitPublishService() (uint16, error) {
model.InitAccounts()
if listener != nil {
if !model.Conf.Publish.Enable {
// 关闭发布服务
closePublishListener()
return 0, nil
}
if port, err := util.ParsePort(Port); err != nil {
return 0, err
} else if port != model.Conf.Publish.Port {
// 关闭原端口的发布服务
if err = closePublishListener(); err != nil {
return 0, err
}
// 重新启动新端口的发布服务
initPublishService()
}
} else {
if !model.Conf.Publish.Enable {
return 0, nil
}
// 启动新端口的发布服务
initPublishService()
}
return util.ParsePort(Port)
}
func initPublishService() (err error) {
if err = initPublishListener(); err == nil {
go startPublishReverseProxyService()
}
return
}
func initPublishListener() (err error) {
// Start new listener
listener, err = net.Listen("tcp", fmt.Sprintf("%s:%d", Host, model.Conf.Publish.Port))
if err != nil {
logging.LogErrorf("start listener failed: %s", err)
return
}
_, Port, err = net.SplitHostPort(listener.Addr().String())
if nil != err {
logging.LogErrorf("split host and port failed: %s", err)
return
}
return
}
func closePublishListener() (err error) {
listener_ := listener
listener = nil
if err = listener_.Close(); err != nil {
logging.LogErrorf("close listener %s failed: %s", listener_.Addr().String(), err)
listener = listener_
}
return
}
func startPublishReverseProxyService() {
logging.LogInfof("publish service [%s:%s] is running", Host, Port)
// 服务进行时一直阻塞
if err := http.Serve(listener, proxy); nil != err {
if listener != nil {
logging.LogErrorf("boot publish service failed: %s", err)
}
}
logging.LogInfof("publish service [%s:%s] is stopped", Host, Port)
}
func rewrite(r *httputil.ProxyRequest) {
r.SetURL(util.ServerURL)
r.SetXForwarded()
// r.Out.Host = r.In.Host // if desired
}
func (PublishServiceTransport) RoundTrip(request *http.Request) (response *http.Response, err error) {
if model.Conf.Publish.Auth.Enable {
// Basic Auth
username, password, ok := request.BasicAuth()
account := model.GetBasicAuthAccount(username)
if !ok ||
account == nil ||
account.Username == "" || // 匿名用户
account.Password != password {
return &http.Response{
StatusCode: http.StatusUnauthorized,
Status: http.StatusText(http.StatusUnauthorized),
Proto: request.Proto,
ProtoMajor: request.ProtoMajor,
ProtoMinor: request.ProtoMinor,
Request: request,
Header: http.Header{
"WWW-Authenticate": {"Basic realm=" + strconv.Quote("Authorization Required")},
},
Close: false,
ContentLength: -1,
}, nil
} else {
// set JWT
request.Header.Set(model.XAuthTokenKey, account.Token)
}
} else {
request.Header.Set(model.XAuthTokenKey, model.GetBasicAuthAccount("").Token)
}
response, err = http.DefaultTransport.RoundTrip(request)
return
}

View file

@ -20,9 +20,9 @@ import (
"bytes"
"fmt"
"html/template"
"mime"
"net"
"net/http"
"net/http/httputil"
"net/http/pprof"
"net/url"
"os"
@ -42,10 +42,13 @@ import (
"github.com/siyuan-note/siyuan/kernel/api"
"github.com/siyuan-note/siyuan/kernel/cmd"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/server/proxy"
"github.com/siyuan-note/siyuan/kernel/util"
)
var cookieStore = cookie.NewStore([]byte("ATN51UlxVq1Gcvdf"))
var (
cookieStore = cookie.NewStore([]byte("ATN51UlxVq1Gcvdf"))
)
func Serve(fastMode bool) {
gin.SetMode(gin.ReleaseMode)
@ -57,6 +60,7 @@ func Serve(fastMode bool) {
model.Timing,
model.Recover,
corsMiddleware(), // 后端服务支持 CORS 预检请求验证 https://github.com/siyuan-note/siyuan/pull/5593
jwtMiddleware, // 解析 JWT https://github.com/siyuan-note/siyuan/issues/11364
gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedExtensions([]string{".pdf", ".mp3", ".wav", ".ogg", ".mov", ".weba", ".mkv", ".mp4", ".webm"})),
)
@ -78,7 +82,10 @@ func Serve(fastMode bool) {
serveEmojis(ginServer)
serveTemplates(ginServer)
servePublic(ginServer)
serveSnippets(ginServer)
serveRepoDiff(ginServer)
serveCheckAuth(ginServer)
serveFixedStaticFiles(ginServer)
api.ServeAPI(ginServer)
var host string
@ -108,34 +115,27 @@ func Serve(fastMode bool) {
}
util.ServerPort = port
util.ServerURL, err = url.Parse("http://127.0.0.1:" + port)
if err != nil {
logging.LogErrorf("parse server url failed: %s", err)
}
pid := fmt.Sprintf("%d", os.Getpid())
if !fastMode {
rewritePortJSON(pid, port)
}
logging.LogInfof("kernel [pid=%s] http server [%s] is booting", pid, host+":"+port)
util.HttpServing = true
go util.HookUILoaded()
go func() {
time.Sleep(1 * time.Second)
if util.FixedPort != port {
if isPortOpen(util.FixedPort) {
return
}
// 启动一个 6806 端口的反向代理服务器,这样浏览器扩展才能直接使用 127.0.0.1:6806不用配置端口
serverURL, _ := url.Parse("http://127.0.0.1:" + port)
proxy := httputil.NewSingleHostReverseProxy(serverURL)
logging.LogInfof("reverse proxy server [%s] is booting", host+":"+util.FixedPort)
if proxyErr := http.ListenAndServe(host+":"+util.FixedPort, proxy); nil != proxyErr {
logging.LogWarnf("boot reverse proxy server [%s] failed: %s", serverURL, proxyErr)
}
// 反代服务器启动失败不影响核心服务器启动
}
go proxy.InitFixedPortService(host)
go proxy.InitPublishService()
// 反代服务器启动失败不影响核心服务器启动
}()
go util.HookUILoaded()
if err = http.Serve(ln, ginServer.Handler()); nil != err {
if !fastMode {
logging.LogErrorf("boot kernel failed: %s", err)
@ -196,11 +196,33 @@ func servePublic(ginServer *gin.Engine) {
ginServer.Static("/public/", filepath.Join(util.DataDir, "public"))
}
func serveAppearance(ginServer *gin.Engine) {
ginServer.StaticFile("favicon.ico", filepath.Join(util.WorkingDir, "stage", "icon.png"))
ginServer.StaticFile("manifest.json", filepath.Join(util.WorkingDir, "stage", "manifest.webmanifest"))
ginServer.StaticFile("manifest.webmanifest", filepath.Join(util.WorkingDir, "stage", "manifest.webmanifest"))
func serveSnippets(ginServer *gin.Engine) {
ginServer.Handle("GET", "/snippets/*filepath", func(c *gin.Context) {
filePath := strings.TrimPrefix(c.Request.URL.Path, "/snippets/")
ext := filepath.Ext(filePath)
name := strings.TrimSuffix(filePath, ext)
confSnippets, err := model.LoadSnippets()
if nil != err {
logging.LogErrorf("load snippets failed: %s", err)
c.Status(http.StatusNotFound)
return
}
for _, s := range confSnippets {
if s.Name == name && ("" != ext && s.Type == ext[1:]) {
c.Header("Content-Type", mime.TypeByExtension(ext))
c.String(http.StatusOK, s.Content)
return
}
}
// 没有在配置文件中命中时在文件系统上查找
filePath = filepath.Join(util.SnippetsPath, filePath)
c.File(filePath)
})
}
func serveAppearance(ginServer *gin.Engine) {
siyuan := ginServer.Group("", model.CheckAuth)
siyuan.Handle("GET", "/", func(c *gin.Context) {
@ -295,12 +317,13 @@ func serveAppearance(ginServer *gin.Engine) {
})
siyuan.Static("/stage/", filepath.Join(util.WorkingDir, "stage"))
ginServer.StaticFile("service-worker.js", filepath.Join(util.WorkingDir, "stage", "service-worker.js"))
siyuan.GET("/check-auth", serveCheckAuth)
}
func serveCheckAuth(c *gin.Context) {
func serveCheckAuth(ginServer *gin.Engine) {
ginServer.GET("/check-auth", serveAuthPage)
}
func serveAuthPage(c *gin.Context) {
data, err := os.ReadFile(filepath.Join(util.WorkingDir, "stage/auth.html"))
if nil != err {
logging.LogErrorf("load auth page failed: %s", err)
@ -363,20 +386,20 @@ func serveCheckAuth(c *gin.Context) {
}
func serveAssets(ginServer *gin.Engine) {
ginServer.POST("/upload", model.CheckAuth, model.Upload)
ginServer.POST("/upload", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, model.Upload)
ginServer.GET("/assets/*path", model.CheckAuth, func(context *gin.Context) {
requestPath := context.Param("path")
relativePath := path.Join("assets", requestPath)
p, err := model.GetAssetAbsPath(relativePath)
if nil != err {
context.Status(404)
context.Status(http.StatusNotFound)
return
}
http.ServeFile(context.Writer, context.Request, p)
return
})
ginServer.GET("/history/*path", model.CheckAuth, func(context *gin.Context) {
ginServer.GET("/history/*path", model.CheckAuth, model.CheckAdminRole, func(context *gin.Context) {
p := filepath.Join(util.HistoryDir, context.Param("path"))
http.ServeFile(context.Writer, context.Request, p)
return
@ -384,7 +407,7 @@ func serveAssets(ginServer *gin.Engine) {
}
func serveRepoDiff(ginServer *gin.Engine) {
ginServer.GET("/repo/diff/*path", model.CheckAuth, func(context *gin.Context) {
ginServer.GET("/repo/diff/*path", model.CheckAuth, model.CheckAdminRole, func(context *gin.Context) {
requestPath := context.Param("path")
p := filepath.Join(util.TempDir, "repo", "diff", requestPath)
http.ServeFile(context.Writer, context.Request, p)
@ -451,6 +474,17 @@ func serveWebSocket(ginServer *gin.Engine) {
}
}
// REF: https://github.com/siyuan-note/siyuan/issues/11364
if !authOk {
if token := model.ParseXAuthToken(s.Request); token != nil {
authOk = token.Valid && model.IsValidRole(model.GetClaimRole(model.GetTokenClaims(token)), []model.Role{
model.RoleAdministrator,
model.RoleEditor,
model.RoleReader,
})
}
}
if !authOk {
// 用于授权页保持连接,避免非常驻内存内核自动退出 https://github.com/siyuan-note/insider/issues/1099
authOk = strings.Contains(s.Request.RequestURI, "/ws?app=siyuan&id=auth")
@ -516,12 +550,24 @@ func serveWebSocket(ginServer *gin.Engine) {
s.Write(result.Bytes())
return
}
if util.ReadOnly && !command.IsRead() {
result := util.NewResult()
result.Code = -1
result.Msg = model.Conf.Language(34)
s.Write(result.Bytes())
return
if !command.IsRead() {
readonly := util.ReadOnly
if !readonly {
if token := model.ParseXAuthToken(s.Request); token != nil {
readonly = token.Valid && model.IsValidRole(model.GetClaimRole(model.GetTokenClaims(token)), []model.Role{
model.RoleReader,
model.RoleVisitor,
})
}
}
if readonly {
result := util.NewResult()
result.Code = -1
result.Msg = model.Conf.Language(34)
s.Write(result.Bytes())
return
}
}
end := time.Now()
@ -564,3 +610,30 @@ func corsMiddleware() gin.HandlerFunc {
c.Next()
}
}
// jwtMiddleware is a middleware to check jwt token
// REF: https://github.com/siyuan-note/siyuan/issues/11364
func jwtMiddleware(c *gin.Context) {
if token := model.ParseXAuthToken(c.Request); token != nil {
// c.Request.Header.Del(model.XAuthTokenKey)
if token.Valid {
claims := model.GetTokenClaims(token)
c.Set(model.ClaimsContextKey, claims)
c.Set(model.RoleContextKey, model.GetClaimRole(claims))
c.Next()
return
}
}
c.Set(model.RoleContextKey, model.RoleVisitor)
c.Next()
return
}
func serveFixedStaticFiles(ginServer *gin.Engine) {
ginServer.StaticFile("favicon.ico", filepath.Join(util.WorkingDir, "stage", "icon.png"))
ginServer.StaticFile("manifest.json", filepath.Join(util.WorkingDir, "stage", "manifest.webmanifest"))
ginServer.StaticFile("manifest.webmanifest", filepath.Join(util.WorkingDir, "stage", "manifest.webmanifest"))
ginServer.StaticFile("service-worker.js", filepath.Join(util.WorkingDir, "stage", "service-worker.js"))
}

View file

@ -18,10 +18,11 @@ package sql
import (
"database/sql"
"github.com/siyuan-note/filelock"
"path/filepath"
"strings"
"github.com/siyuan-note/filelock"
"github.com/88250/lute/ast"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/treenode"

View file

@ -20,6 +20,7 @@ import (
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
@ -90,6 +91,19 @@ func IsOnline(checkURL string, skipTlsVerify bool) bool {
return false
}
func IsPortOpen(port string) bool {
timeout := time.Second
conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", port), timeout)
if nil != err {
return false
}
if nil != conn {
conn.Close()
return true
}
return false
}
func isOnline(checkURL string, skipTlsVerify bool) (ret bool) {
c := req.C().SetTimeout(3 * time.Second)
if skipTlsVerify {
@ -168,3 +182,12 @@ func initHttpClient() {
http.DefaultClient = httpclient.GetCloudFileClient2Min()
http.DefaultTransport = httpclient.NewTransport(false)
}
func ParsePort(portString string) (uint16, error) {
if port, err := strconv.ParseUint(portString, 10, 16); err != nil {
logging.LogErrorf("parse port [%s] failed: %s", portString, err)
return 0, err
} else {
return uint16(port), nil
}
}

View file

@ -269,6 +269,7 @@ func IsDisplayableAsset(p string) bool {
func GetAbsPathInWorkspace(relPath string) (string, error) {
absPath := filepath.Join(WorkspaceDir, relPath)
absPath = filepath.Clean(absPath)
if WorkspaceDir == absPath {
return absPath, nil
}

View file

@ -22,6 +22,7 @@ import (
"fmt"
"math/rand"
"mime"
"net/url"
"os"
"path/filepath"
"runtime"
@ -341,7 +342,9 @@ func WriteWorkspacePaths(workspacePaths []string) (err error) {
}
var (
ServerPort = "0" // HTTP/WebSocket 端口0 为使用随机端口
ServerURL *url.URL // 内核服务 URL
ServerPort = "0" // HTTP/WebSocket 端口0 为使用随机端口
ReadOnly bool
AccessAuthCode string
Lang = ""