mirror of
https://github.com/zhaojh329/rttys.git
synced 2026-02-27 09:53:21 +08:00
Support connect devices with no web login required
Example: http://localhost:5913/connect/rtty1 http://localhost:5913/connect/rtty2 Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
This commit is contained in:
@@ -48,6 +48,8 @@ This is the server program of [rtty](https://github.com/zhaojh329/rtty)
|
||||
keyFile Path
|
||||
-token string
|
||||
token to use
|
||||
-white-list string
|
||||
white list(device IDs separated by spaces or *)
|
||||
|
||||
## Authorization
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
keyFile Path
|
||||
-token string
|
||||
token to use
|
||||
-white-list string
|
||||
white list(device IDs separated by spaces or *)
|
||||
|
||||
## 认证
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ type CommandStatus struct {
|
||||
}
|
||||
|
||||
type CommandInfo struct {
|
||||
Devid string `json:"devid"`
|
||||
Cmd string `json:"cmd"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
@@ -47,6 +46,7 @@ type CommandReq struct {
|
||||
done chan struct{}
|
||||
token string
|
||||
content []byte
|
||||
devid string
|
||||
w http.ResponseWriter
|
||||
}
|
||||
|
||||
@@ -87,12 +87,12 @@ func handleCmdReq(br *Broker, req *CommandReq) {
|
||||
|
||||
cmdInfo := CommandInfo{}
|
||||
err := jsoniter.Unmarshal(req.content, &cmdInfo)
|
||||
if err != nil || cmdInfo.Cmd == "" || cmdInfo.Devid == "" {
|
||||
if err != nil || cmdInfo.Cmd == "" {
|
||||
cmdErrReply(RttyCmdErrInvalid, req)
|
||||
return
|
||||
}
|
||||
|
||||
dev, ok := br.devices[cmdInfo.Devid]
|
||||
dev, ok := br.devices[req.devid]
|
||||
if !ok {
|
||||
cmdErrReply(RttyCmdErrOffline, req)
|
||||
return
|
||||
|
||||
26
config.go
26
config.go
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RttysConfig struct {
|
||||
@@ -17,6 +18,7 @@ type RttysConfig struct {
|
||||
httpPassword string
|
||||
token string
|
||||
fontSize int
|
||||
whiteList map[string]bool
|
||||
}
|
||||
|
||||
func getConfigOpt(yamlCfg *yaml.File, name string, opt interface{}) {
|
||||
@@ -36,6 +38,8 @@ func getConfigOpt(yamlCfg *yaml.File, name string, opt interface{}) {
|
||||
func parseConfig() *RttysConfig {
|
||||
cfg := &RttysConfig{}
|
||||
|
||||
cfg.whiteList = make(map[string]bool)
|
||||
|
||||
flag.StringVar(&cfg.addrDev, "addr-dev", ":5912", "address to listen device")
|
||||
flag.StringVar(&cfg.addrUser, "addr-user", ":5913", "address to listen user")
|
||||
flag.StringVar(&cfg.sslCert, "ssl-cert", "", "certFile Path")
|
||||
@@ -43,9 +47,20 @@ func parseConfig() *RttysConfig {
|
||||
flag.StringVar(&cfg.httpUsername, "http-username", "", "username for http auth")
|
||||
flag.StringVar(&cfg.httpPassword, "http-password", "", "password for http auth")
|
||||
flag.StringVar(&cfg.token, "token", "", "token to use")
|
||||
|
||||
conf := flag.String("conf", "./rttys.conf", "config file to load")
|
||||
genToken := flag.Bool("gen-token", false, "generate token")
|
||||
|
||||
whiteList := flag.String("white-list", "", "white list(device IDs separated by spaces or *)")
|
||||
|
||||
if *whiteList == "*" {
|
||||
cfg.whiteList = nil
|
||||
} else {
|
||||
for _, id := range strings.Fields(*whiteList) {
|
||||
cfg.whiteList[id] = true
|
||||
}
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *genToken {
|
||||
@@ -62,6 +77,17 @@ func parseConfig() *RttysConfig {
|
||||
getConfigOpt(yamlCfg, "http-password", &cfg.httpPassword)
|
||||
getConfigOpt(yamlCfg, "token", &cfg.token)
|
||||
getConfigOpt(yamlCfg, "font-size", &cfg.fontSize)
|
||||
|
||||
val, err := yamlCfg.Get("white-list")
|
||||
if err == nil {
|
||||
if val == "*" || val == "\"*\"" {
|
||||
cfg.whiteList = nil
|
||||
} else {
|
||||
for _, id := range strings.Fields(val) {
|
||||
cfg.whiteList[id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.fontSize == 0 {
|
||||
|
||||
@@ -31,6 +31,17 @@ const router = new VueRouter({
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.matched.length > 0 && to.matched[0].path === '/rtty/:devid') {
|
||||
const devid = to.params['devid'];
|
||||
Vue.axios.get(`/authorized/${devid}`).then(r => {
|
||||
if (r.data.authorized)
|
||||
next();
|
||||
else
|
||||
router.push('/login');
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.path !== '/login' && !sessionStorage.getItem('rtty-sid')) {
|
||||
router.push('/login');
|
||||
return;
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
|
||||
item.querying = true;
|
||||
|
||||
this.axios.get(process.env.BASE_URL + 'cmd?token=' + token).then(response => {
|
||||
this.axios.get(`/cmd/${item.devid}/${token}`).then(response => {
|
||||
const resp = response.data as ResponseInfo;
|
||||
|
||||
if (resp.err === 1005) {
|
||||
@@ -308,7 +308,6 @@
|
||||
|
||||
this.selection.forEach(item => {
|
||||
const data = {
|
||||
devid: item.id,
|
||||
username: this.cmdData.username,
|
||||
password: this.cmdData.password,
|
||||
sid: sessionStorage.getItem('rtty-sid'),
|
||||
@@ -316,7 +315,7 @@
|
||||
params: this.cmdData.params
|
||||
};
|
||||
|
||||
this.axios.post(process.env.BASE_URL + 'cmd', data).then((response) => {
|
||||
this.axios.post(`/cmd/${item.id}`, data).then((response) => {
|
||||
const resp = response.data as ResponseInfo;
|
||||
|
||||
if (resp.token) {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
updateFontSize(size: number) {
|
||||
this.term?.setOption('fontSize', size);
|
||||
this.fitAddon?.fit();
|
||||
this.axios.post('/fontsize', 'size=' + size);
|
||||
this.axios.post(`/fontsize/${this.devid}`, {size});
|
||||
}
|
||||
|
||||
onUploadDialogClosed() {
|
||||
@@ -238,8 +238,8 @@
|
||||
this.socket = socket;
|
||||
|
||||
socket.addEventListener('open', () => {
|
||||
this.axios.get('/fontsize').then(r => {
|
||||
this.term?.setOption('fontSize', parseInt(r.data));
|
||||
this.axios.get(`/fontsize/${this.devid}`).then(r => {
|
||||
this.term?.setOption('fontSize', r.data.size);
|
||||
this.fitTerm();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,14 +21,17 @@ module.exports = {
|
||||
'/signin': {
|
||||
target: 'http://127.0.0.1:5913'
|
||||
},
|
||||
'/cmd': {
|
||||
'/cmd/*': {
|
||||
target: 'http://127.0.0.1:5913'
|
||||
},
|
||||
'/connect/*': {
|
||||
ws: true,
|
||||
target: 'http://127.0.0.1:5913'
|
||||
},
|
||||
'/fontsize': {
|
||||
'/fontsize/*': {
|
||||
target: 'http://127.0.0.1:5913'
|
||||
},
|
||||
'/authorized/*': {
|
||||
target: 'http://127.0.0.1:5913'
|
||||
}
|
||||
}
|
||||
|
||||
58
http.go
58
http.go
@@ -10,7 +10,6 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -39,6 +38,15 @@ func httpLogin(cfg *RttysConfig, creds *Credentials) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func authorizedDev(devid string, cfg *RttysConfig) bool {
|
||||
if cfg.whiteList == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
_, ok := cfg.whiteList[devid]
|
||||
return ok
|
||||
}
|
||||
|
||||
func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
httpSessions = cache.New(30*time.Minute, 5*time.Second)
|
||||
|
||||
@@ -47,6 +55,11 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
r := gin.New()
|
||||
|
||||
authorized := r.Group("/", func(c *gin.Context) {
|
||||
devid := c.Param("devid")
|
||||
if devid != "" && authorizedDev(devid, cfg) {
|
||||
return
|
||||
}
|
||||
|
||||
cookie, err := c.Cookie("sid")
|
||||
if err != nil || !httpSessions.Have(cookie) {
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
@@ -58,19 +71,30 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
httpSessions.Set(cookie, true, 0)
|
||||
})
|
||||
|
||||
authorized.GET("/fontsize", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "%d", cfg.fontSize)
|
||||
authorized.GET("/fontsize/:devid", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"size": cfg.fontSize})
|
||||
})
|
||||
|
||||
authorized.POST("/fontsize", func(c *gin.Context) {
|
||||
size, err := strconv.Atoi(c.PostForm("size"))
|
||||
if err == nil {
|
||||
cfg.fontSize = size
|
||||
authorized.POST("/fontsize/:devid", func(c *gin.Context) {
|
||||
type Resp struct {
|
||||
Size int `json:"size"`
|
||||
}
|
||||
var r Resp
|
||||
err := c.BindJSON(&r)
|
||||
if err != nil {
|
||||
c.Status(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
cfg.fontSize = r.Size
|
||||
c.String(http.StatusOK, "OK")
|
||||
})
|
||||
|
||||
authorized.GET("/connect/:devid", func(c *gin.Context) {
|
||||
if c.GetHeader("Upgrade") != "websocket" {
|
||||
c.Redirect(http.StatusFound, "/rtty/"+c.Param("devid"))
|
||||
return
|
||||
}
|
||||
serveUser(br, c)
|
||||
})
|
||||
|
||||
@@ -93,7 +117,7 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
c.JSON(http.StatusOK, devs)
|
||||
})
|
||||
|
||||
authorized.GET("/cmd", func(c *gin.Context) {
|
||||
authorized.GET("/cmd/:devid/:token", func(c *gin.Context) {
|
||||
allowOrigin(c.Writer)
|
||||
|
||||
done := make(chan struct{})
|
||||
@@ -102,19 +126,20 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
w: c.Writer,
|
||||
}
|
||||
|
||||
req.token = c.Query("token")
|
||||
req.token = c.Param("token")
|
||||
|
||||
br.cmdReq <- req
|
||||
<-done
|
||||
})
|
||||
|
||||
authorized.POST("/cmd", func(c *gin.Context) {
|
||||
authorized.POST("/cmd/:devid", func(c *gin.Context) {
|
||||
allowOrigin(c.Writer)
|
||||
|
||||
done := make(chan struct{})
|
||||
req := &CommandReq{
|
||||
done: done,
|
||||
w: c.Writer,
|
||||
done: done,
|
||||
w: c.Writer,
|
||||
devid: c.Param("devid"),
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(c.Request.Body)
|
||||
@@ -135,6 +160,12 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
<-done
|
||||
})
|
||||
|
||||
r.GET("/authorized/:devid", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"authorized": authorizedDev(c.Param("devid"), cfg),
|
||||
})
|
||||
})
|
||||
|
||||
r.POST("/signin", func(c *gin.Context) {
|
||||
var creds Credentials
|
||||
|
||||
@@ -164,7 +195,8 @@ func httpStart(br *Broker, cfg *RttysConfig) {
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
f, err := statikFS.Open(path.Clean(c.Request.URL.Path))
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/")
|
||||
c.Request.URL.Path = "/"
|
||||
r.HandleContext(c)
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
|
||||
@@ -12,4 +12,11 @@ http-password: rttys
|
||||
|
||||
#token: a1d4cdb1a3cd6a0e94aa3599afcddcf5
|
||||
|
||||
# font-size: 16
|
||||
# font-size: 16
|
||||
|
||||
# No login required to connect device.
|
||||
# Values can be device IDs separated by spaces,
|
||||
# or a "*" indicates that all devices do not require login
|
||||
# http://localhost:5913/connect/rtty1
|
||||
#white-list: "*"
|
||||
#white-list: rtty1 rtty2
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user