mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-01-14 20:58:51 +01:00
✨ Support read-only publish service
* 🎨 kernel supports read-only publishing services * 🐛 Fix authentication vulnerabilities * 🎨 Protect secret information * 🎨 Adjust the permission control * 🎨 Adjust the permission control * 🎨 Fixed the vulnerability that `getFile` gets file `conf.json` * 🎨 Add API `/api/setting/setPublish` * 🎨 Add API `/api/setting/getPublish` * 🐛 Fixed the issue that PWA-related files could not pass BasicAuth * 🎨 Add a settings panel for publishing features * 📝 Add guide for `Publish Service` * 📝 Update Japanese user guide * 🎨 Merge fixed static file services
This commit is contained in:
parent
536879cb84
commit
ba2193403d
47 changed files with 3690 additions and 375 deletions
41
kernel/server/proxy/fixedport.go
Normal file
41
kernel/server/proxy/fixedport.go
Normal 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)
|
||||
}
|
||||
}
|
||||
161
kernel/server/proxy/publish.go
Normal file
161
kernel/server/proxy/publish.go
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue