Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2024-06-12 22:32:24 +08:00
commit 249f836d9e
54 changed files with 3772 additions and 430 deletions

View file

@ -14,10 +14,10 @@ Install pnpm: `npm install -g pnpm@9.1.1`
Set the Electron mirror environment variable and install Electron:
* macOS/Linux: `ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ pnpm install electron@28.3.1 -D`
* macOS/Linux: `ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ pnpm install electron@28.3.3 -D`
* Windows:
* `SET ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`
* `pnpm install electron@28.3.1 -D`
* `pnpm install electron@28.3.3 -D`
NPM mirror:
@ -28,7 +28,7 @@ NPM mirror:
On the desktop, go to the app folder to run:
* `pnpm install electron@28.3.1 -D`
* `pnpm install electron@28.3.3 -D`
* `pnpm run dev`
* `pnpm run start`

View file

@ -16,11 +16,11 @@
* macOS/Linux:
```
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ pnpm install electron@28.3.1 -D
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ pnpm install electron@28.3.3 -D
```
* Windows:
* `SET ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`
* `pnpm install electron@28.3.1 -D`
* `pnpm install electron@28.3.3 -D`
NPM 镜像:
@ -30,7 +30,7 @@ NPM 镜像:
桌面端进入 app 文件夹运行:
* `pnpm install electron@28.3.1 -D`
* `pnpm install electron@28.3.3 -D`
* `pnpm run dev`
* `pnpm run start`

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,531 @@
{
"ID": "20240517031132-jmr5ihm",
"Spec": "1",
"Type": "NodeDocument",
"Properties": {
"id": "20240517031132-jmr5ihm",
"title": "Publish service",
"type": "doc",
"updated": "20240612211244"
},
"Children": [
{
"ID": "20240517031304-um049u9",
"Type": "NodeHeading",
"HeadingLevel": 2,
"Properties": {
"id": "20240517031304-um049u9",
"updated": "20240612211244"
},
"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": "20240612211244"
},
"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": "20240612211244"
},
"Children": [
{
"Type": "NodeTextMark",
"TextMarkType": "tag",
"TextMarkTextContent": "Note"
},
{
"Type": "NodeText",
"Data": ""
}
]
},
{
"ID": "20240517031304-3slh48m",
"Type": "NodeList",
"ListData": {},
"Properties": {
"id": "20240517031304-3slh48m",
"updated": "20240612211244"
},
"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

@ -55,7 +55,7 @@
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.7.1",
"dayjs": "^1.11.5",
"electron": "28.3.1",
"electron": "28.3.3",
"electron-builder": "24.9.1",
"encoding": "^0.1.13",
"esbuild-loader": "^3.0.1",

83
app/pnpm-lock.yaml generated
View file

@ -10,14 +10,14 @@ importers:
dependencies:
'@electron/remote':
specifier: ^2.1.2
version: 2.1.2(electron@28.3.1)
version: 2.1.2(electron@28.3.3)
devDependencies:
'@types/node':
specifier: ^18.13.0
version: 18.13.0
'@typescript-eslint/eslint-plugin':
specifier: ^5.30.6
version: 5.30.6(@typescript-eslint/parser@5.30.6)(eslint@8.19.0)(typescript@4.7.4)
version: 5.30.6(@typescript-eslint/parser@5.30.6(eslint@8.19.0)(typescript@4.7.4))(eslint@8.19.0)(typescript@4.7.4)
'@typescript-eslint/parser':
specifier: ^5.30.6
version: 5.30.6(eslint@8.19.0)(typescript@4.7.4)
@ -26,16 +26,16 @@ importers:
version: 2.19.0
clean-webpack-plugin:
specifier: ^4.0.0
version: 4.0.0(webpack@5.76.0)
version: 4.0.0(webpack@5.76.0(webpack-cli@4.10.0))
css-loader:
specifier: ^6.7.1
version: 6.7.1(webpack@5.76.0)
version: 6.7.1(webpack@5.76.0(webpack-cli@4.10.0))
dayjs:
specifier: ^1.11.5
version: 1.11.5
electron:
specifier: 28.3.1
version: 28.3.1
specifier: 28.3.3
version: 28.3.3
electron-builder:
specifier: 24.9.1
version: 24.9.1
@ -44,19 +44,19 @@ importers:
version: 0.1.13
esbuild-loader:
specifier: ^3.0.1
version: 3.0.1(webpack@5.76.0)
version: 3.0.1(webpack@5.76.0(webpack-cli@4.10.0))
eslint:
specifier: ^8.19.0
version: 8.19.0
file-loader:
specifier: ^6.2.0
version: 6.2.0(webpack@5.76.0)
version: 6.2.0(webpack@5.76.0(webpack-cli@4.10.0))
html-loader:
specifier: ^2.1.2
version: 2.1.2(webpack@5.76.0)
version: 2.1.2(webpack@5.76.0(webpack-cli@4.10.0))
html-webpack-plugin:
specifier: ^5.5.0
version: 5.5.0(webpack@5.76.0)
version: 5.5.0(webpack@5.76.0(webpack-cli@4.10.0))
iconv-lite:
specifier: ^0.6.3
version: 0.6.3
@ -65,7 +65,7 @@ importers:
version: 2.3.2
mini-css-extract-plugin:
specifier: 2.7.6
version: 2.7.6(webpack@5.76.0)
version: 2.7.6(webpack@5.76.0(webpack-cli@4.10.0))
path-browserify:
specifier: ^1.0.1
version: 1.0.1
@ -77,7 +77,7 @@ importers:
version: 1.53.0
sass-loader:
specifier: ^12.6.0
version: 12.6.0(sass@1.53.0)(webpack@5.76.0)
version: 12.6.0(sass@1.53.0)(webpack@5.76.0(webpack-cli@4.10.0))
typescript:
specifier: ^4.7.4
version: 4.7.4
@ -922,8 +922,8 @@ packages:
electron-to-chromium@1.4.186:
resolution: {integrity: sha512-YoVeFrGd/7ROjz4R9uPoND1K/hSRC/xADy9639ZmIZeJSaBnKdYx3I6LMPsY7CXLpK7JFgKQVzeZ/dk2br6Eaw==}
electron@28.3.1:
resolution: {integrity: sha512-aF9fONuhVDJlctJS7YOw76ynxVAQdfIWmlhRMKits24tDcdSL0eMHUS0wWYiRfGWbQnUKB6V49Rf17o32f4/fg==}
electron@28.3.3:
resolution: {integrity: sha512-ObKMLSPNhomtCOBAxFS8P2DW/4umkh72ouZUlUKzXGtYuPzgr1SYhskhFWgzAsPtUzhL2CzyV2sfbHcEW4CXqw==}
engines: {node: '>= 12.20.55'}
hasBin: true
@ -2243,9 +2243,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@electron/remote@2.1.2(electron@28.3.1)':
'@electron/remote@2.1.2(electron@28.3.3)':
dependencies:
electron: 28.3.1
electron: 28.3.3
'@electron/universal@1.4.1':
dependencies:
@ -2472,7 +2472,7 @@ snapshots:
'@types/node': 18.13.0
optional: true
'@typescript-eslint/eslint-plugin@5.30.6(@typescript-eslint/parser@5.30.6)(eslint@8.19.0)(typescript@4.7.4)':
'@typescript-eslint/eslint-plugin@5.30.6(@typescript-eslint/parser@5.30.6(eslint@8.19.0)(typescript@4.7.4))(eslint@8.19.0)(typescript@4.7.4)':
dependencies:
'@typescript-eslint/parser': 5.30.6(eslint@8.19.0)(typescript@4.7.4)
'@typescript-eslint/scope-manager': 5.30.6
@ -2485,6 +2485,7 @@ snapshots:
regexpp: 3.2.0
semver: 7.3.8
tsutils: 3.21.0(typescript@4.7.4)
optionalDependencies:
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
@ -2496,6 +2497,7 @@ snapshots:
'@typescript-eslint/typescript-estree': 5.30.6(typescript@4.7.4)
debug: 4.3.4
eslint: 8.19.0
optionalDependencies:
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
@ -2511,6 +2513,7 @@ snapshots:
debug: 4.3.4
eslint: 8.19.0
tsutils: 3.21.0(typescript@4.7.4)
optionalDependencies:
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
@ -2526,6 +2529,7 @@ snapshots:
is-glob: 4.0.3
semver: 7.5.4
tsutils: 3.21.0(typescript@4.7.4)
optionalDependencies:
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
@ -2624,17 +2628,17 @@ snapshots:
'@webassemblyjs/ast': 1.11.1
'@xtuc/long': 4.2.2
'@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0)(webpack@5.76.0)':
'@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))(webpack@5.76.0(webpack-cli@4.10.0))':
dependencies:
webpack: 5.76.0(webpack-cli@4.10.0)
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0)
'@webpack-cli/info@1.5.0(webpack-cli@4.10.0)':
'@webpack-cli/info@1.5.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))':
dependencies:
envinfo: 7.8.1
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0)
'@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)':
'@webpack-cli/serve@1.7.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))':
dependencies:
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0)
@ -2661,7 +2665,7 @@ snapshots:
- supports-color
ajv-formats@2.1.1(ajv@8.12.0):
dependencies:
optionalDependencies:
ajv: 8.12.0
ajv-keywords@3.5.2(ajv@6.12.6):
@ -2892,7 +2896,7 @@ snapshots:
dependencies:
source-map: 0.6.1
clean-webpack-plugin@4.0.0(webpack@5.76.0):
clean-webpack-plugin@4.0.0(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
del: 4.1.1
webpack: 5.76.0(webpack-cli@4.10.0)
@ -2964,7 +2968,7 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
css-loader@6.7.1(webpack@5.76.0):
css-loader@6.7.1(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
icss-utils: 5.1.0(postcss@8.4.31)
postcss: 8.4.31
@ -3128,7 +3132,7 @@ snapshots:
electron-to-chromium@1.4.186: {}
electron@28.3.1:
electron@28.3.3:
dependencies:
'@electron/get': 2.0.2
'@types/node': 18.13.0
@ -3166,7 +3170,7 @@ snapshots:
es6-error@4.1.1:
optional: true
esbuild-loader@3.0.1(webpack@5.76.0):
esbuild-loader@3.0.1(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
esbuild: 0.17.10
get-tsconfig: 4.4.0
@ -3325,7 +3329,7 @@ snapshots:
dependencies:
flat-cache: 3.0.4
file-loader@6.2.0(webpack@5.76.0):
file-loader@6.2.0(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
loader-utils: 2.0.4
schema-utils: 3.1.1
@ -3499,7 +3503,7 @@ snapshots:
dependencies:
lru-cache: 6.0.0
html-loader@2.1.2(webpack@5.76.0):
html-loader@2.1.2(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
html-minifier-terser: 5.1.1
parse5: 6.0.1
@ -3525,7 +3529,7 @@ snapshots:
relateurl: 0.2.7
terser: 5.14.1
html-webpack-plugin@5.5.0(webpack@5.76.0):
html-webpack-plugin@5.5.0(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@ -3772,7 +3776,7 @@ snapshots:
mimic-response@3.1.0: {}
mini-css-extract-plugin@2.7.6(webpack@5.76.0):
mini-css-extract-plugin@2.7.6(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
schema-utils: 4.2.0
webpack: 5.76.0(webpack-cli@4.10.0)
@ -4067,12 +4071,13 @@ snapshots:
dependencies:
truncate-utf8-bytes: 1.0.2
sass-loader@12.6.0(sass@1.53.0)(webpack@5.76.0):
sass-loader@12.6.0(sass@1.53.0)(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
klona: 2.0.5
neo-async: 2.6.2
sass: 1.53.0
webpack: 5.76.0(webpack-cli@4.10.0)
optionalDependencies:
sass: 1.53.0
sass@1.53.0:
dependencies:
@ -4209,7 +4214,7 @@ snapshots:
async-exit-hook: 2.0.1
fs-extra: 10.1.0
terser-webpack-plugin@5.3.3(webpack@5.76.0):
terser-webpack-plugin@5.3.3(webpack@5.76.0(webpack-cli@4.10.0)):
dependencies:
'@jridgewell/trace-mapping': 0.3.14
jest-worker: 27.5.1
@ -4324,9 +4329,9 @@ snapshots:
webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0):
dependencies:
'@discoveryjs/json-ext': 0.5.7
'@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.76.0)
'@webpack-cli/info': 1.5.0(webpack-cli@4.10.0)
'@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0)
'@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))(webpack@5.76.0(webpack-cli@4.10.0))
'@webpack-cli/info': 1.5.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))
'@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0))
colorette: 2.0.19
commander: 7.2.0
cross-spawn: 7.0.3
@ -4335,8 +4340,9 @@ snapshots:
interpret: 2.2.0
rechoir: 0.7.1
webpack: 5.76.0(webpack-cli@4.10.0)
webpack-bundle-analyzer: 4.5.0
webpack-merge: 5.8.0
optionalDependencies:
webpack-bundle-analyzer: 4.5.0
webpack-merge@5.8.0:
dependencies:
@ -4373,10 +4379,11 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.1.1
tapable: 2.2.1
terser-webpack-plugin: 5.3.3(webpack@5.76.0)
terser-webpack-plugin: 5.3.3(webpack@5.76.0(webpack-cli@4.10.0))
watchpack: 2.4.0
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0)
webpack-sources: 3.2.3
optionalDependencies:
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.76.0)
transitivePeerDependencies:
- '@swc/core'
- esbuild

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

@ -404,12 +404,9 @@ func moveTree(tree *parse.Tree) {
func (box *Box) renameSubTrees(tree *parse.Tree) {
subFiles := box.ListFiles(tree.Path)
box.moveTrees0(subFiles)
}
func (box *Box) moveTrees0(files []*FileInfo) {
luteEngine := util.NewLute()
for _, subFile := range files {
for _, subFile := range subFiles {
if !strings.HasSuffix(subFile.path, ".sy") {
continue
}

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")

View file

@ -1477,7 +1477,8 @@ func moveDoc(fromBox *Box, fromPath string, toBox *Box, toPath string, luteEngin
}
}
if fromBox.Exist(fromFolder) {
needMoveSubDocs := fromBox.Exist(fromFolder)
if needMoveSubDocs {
// 移动子文档文件夹
newFolder := path.Join(toFolder, tree.ID)
@ -1532,6 +1533,28 @@ func moveDoc(fromBox *Box, fromPath string, toBox *Box, toPath string, luteEngin
moveSorts(tree.ID, fromBox.ID, toBox.ID)
}
if needMoveSubDocs {
// 将其所有子文档的移动事件推送到前端 https://github.com/siyuan-note/siyuan/issues/11661
subDocsFolder := path.Join(toFolder, tree.ID)
syFiles := listSyFiles(path.Join(toBox.ID, subDocsFolder))
for _, syFile := range syFiles {
relPath := strings.TrimPrefix(syFile, "/"+path.Join(toBox.ID, toFolder))
subFromPath := path.Join(path.Dir(fromPath), relPath)
subToPath := path.Join(toFolder, relPath)
evt := util.NewCmdResult("moveDoc", 0, util.PushModeBroadcast)
evt.Data = map[string]interface{}{
"fromNotebook": fromBox.ID,
"fromPath": subFromPath,
"toNotebook": toBox.ID,
"toPath": path.Dir(subToPath) + ".sy",
"newPath": subToPath,
}
evt.Callback = callback
util.PushEvent(evt)
}
}
evt := util.NewCmdResult("moveDoc", 0, util.PushModeBroadcast)
evt.Data = map[string]interface{}{
"fromNotebook": fromBox.ID,

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

@ -851,11 +851,6 @@ func FullTextSearchBlock(query string, boxes, paths []string, types map[string]b
query = trimQuery
}
if 1 == groupBy {
// 按文档分组时使用搜索设置限制 Search `Group by doc` follows the search setting limit display https://github.com/siyuan-note/siyuan/issues/11667
pageSize = Conf.Search.Limit
}
beforeLen := 36
var blocks []*Block
orderByClause := buildOrderBy(query, method, orderBy)

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 = ""