123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Package sso 群辉登录
- package sso
- import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "log"
- "net/url"
- "os"
- "os/exec"
- "regexp"
- "strings"
- )
- // AppPrivilege is part of AuthJSON
- type AppPrivilege struct {
- IsPermitted bool `json:"SYNO.SDS.DNSCryptProxy.Application"`
- }
- // Session is part of AuthJSON
- type Session struct {
- IsAdmin bool `json:"is_admin"`
- }
- // AuthJSON is used to read JSON data from /usr/syno/synoman/webman/initdata.cgi
- type AuthJSON struct {
- Session Session `json:"session"`
- AppPrivilege AppPrivilege
- }
- type RespJSON struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data any `json:"data"`
- }
- type UserData struct {
- User string `json:"user"`
- SynoToken string `json:"synoToken"`
- Data string `json:"data"`
- }
- type SynoResp struct {
- StatusCode int
- Message string
- Data UserData
- Ok bool
- }
- func (r *SynoResp) PrintNoData() {
- fmt.Print(r.Message)
- }
- func OkResp() SynoResp {
- return SynoResp{
- StatusCode: 200,
- Message: "Status: 200 OK\nContent-Type: application/json; charset=utf-8\n\n",
- Ok: true,
- }
- }
- func UnauthorisedResp() SynoResp {
- return SynoResp{
- StatusCode: 401,
- Message: "Status: 401 Unauthorized\nContent-Type: text/html; charset=utf-8\n\n",
- Ok: false,
- }
- }
- func ErrorResp() SynoResp {
- return SynoResp{
- StatusCode: 500,
- Message: "Status: 500 Internal server error\nContent-Type: text/html; charset=utf-8\n\n",
- Ok: false,
- }
- }
- // Retrieve login status and try to retrieve a CSRF token.
- // If either fails than we return an error to the user that they need to login.
- // Returns username or error
- // 现在没有权限访问这个,需要客户端进行调用
- func token() (string, error) {
- cmd := exec.Command("/usr/syno/synoman/webman/login.cgi")
- cmdOut, err := cmd.Output()
- if err != nil && err.Error() != "exit status 255" { // in the Synology world, error code 255 apparently means success!
- return string(cmdOut), err
- }
- // cmdOut = bytes.TrimLeftFunc(cmdOut, findJSON)
- // Content-Type: text/html [..] { "SynoToken" : "GqHdJil0ZmlhE", "result" : "success", "success" : true }
- r, err := regexp.Compile("SynoToken\" *: *\"([^\"]+)\"")
- if err != nil {
- return string(cmdOut), err
- }
- token := r.FindSubmatch(cmdOut)
- if len(token) < 1 {
- return string(cmdOut), errors.New("Sorry, you need to login first!")
- }
- return string(token[1]), nil
- }
- // Detect if the rune (character) contains '{' and therefore is likely to contain JSON
- // returns bool
- func findJSON(r rune) bool {
- if r == '{' {
- return false
- }
- return true
- }
- // Check if the logged in user is Authorised or Admin.
- // If either fails than we return a HTTP Unauthorized error.
- func SynoAuth() SynoResp {
- //to, err := token()
- //if err != nil {
- // log.Println("getToken fail", err)
- // return UnauthorisedResp()
- //} else {
- // log.Println("getToken ok...", to)
- //}
- // X-SYNO-TOKEN:9WuK4Cf50Vw7Q
- // http://192.168.1.1:5000/webman/3rdparty/DownloadStation/webUI/downloadman.cgi?SynoToken=9WuK4Cf50Vw7Q
- tempQueryEnv := os.Getenv("QUERY_STRING")
- log.Println("tempQueryEnv: ", tempQueryEnv)
- if tempQueryEnv == "" || !strings.Contains(tempQueryEnv, "SynoToken") {
- log.Println("query str miss SynoToken")
- return ErrorResp()
- }
- u, err := url.Parse(fmt.Sprintf("http://test.example.cn/?%s", tempQueryEnv))
- if err != nil {
- log.Println("parse query params fail: ", err)
- return ErrorResp()
- }
- query := u.Query()
- tokenStr := query.Get("SynoToken")
- log.Println("tokenStr: ", tokenStr)
- //os.Setenv("QUERY_STRING", "SynoToken="+to)
- cmd := exec.Command("/usr/syno/synoman/webman/modules/authenticate.cgi")
- user, err := cmd.Output()
- if err != nil && string(user) == "" {
- log.Println("authenticate fail", err)
- return UnauthorisedResp()
- }
- log.Println("user: ", string(user))
- account := strings.NewReplacer("\r", "").Replace(string(user))
- account = strings.NewReplacer("\n", "").Replace(account)
- var userData = UserData{
- User: account,
- SynoToken: tokenStr,
- }
- // check permissions
- if checkIfFileExists("/usr/syno/synoman/webman/initdata.cgi") {
- cmd = exec.Command("/usr/syno/synoman/webman/initdata.cgi") // performance hit
- cmdOut, err := cmd.Output()
- if err != nil {
- log.Println("initdata fail", err)
- //unauthorised()
- }
- cmdOut = bytes.TrimLeftFunc(cmdOut, findJSON)
- var jsonData AuthJSON
- if err := json.Unmarshal(cmdOut, &jsonData); err != nil { // performance hit
- log.Println("initdata Unmarshal fail", err)
- //unauthorised()
- }
- isAdmin := jsonData.Session.IsAdmin // Session.IsAdmin:true
- isPermitted := jsonData.AppPrivilege.IsPermitted // AppPrivilege.SYNO.SDS.DNSCryptProxy.Application:true
- if !(isAdmin || isPermitted) {
- log.Println("initdata Unmarshal fail", err)
- //unauthorised()
- }
- }
- //os.Setenv("QUERY_STRING", tempQueryEnv)
- resp := OkResp()
- resp.Data = userData
- return resp
- }
- // Return true if the file path exists.
- func checkIfFileExists(file string) bool {
- _, err := os.Stat(file)
- if err != nil {
- if os.IsNotExist(err) {
- return false
- }
- log.Printf("checkIfFileExists error: %v", err)
- }
- return true
- }
|