package rtc import ( "bytes" cr "crypto/rand" "crypto/sha256" "encoding/hex" "errors" "gowebsocket/common" "gowebsocket/controllers" // "flag" "fmt" "os" "time" "github.com/gin-gonic/gin" oh "github.com/ossrs/go-oryx-lib/http" ol "github.com/ossrs/go-oryx-lib/logger" "github.com/spf13/viper" "github.com/twinj/uuid" ) func CreateUserID(channelID, user string) string { var b bytes.Buffer b.WriteString(channelID) b.WriteString("/") b.WriteString(user) h := sha256.New() if _, err := h.Write([]byte(b.String())); err != nil { return BuildRandom(16) } s := h.Sum(nil) uid := hex.EncodeToString(s) return uid[:16] } func CreateToken( appID, appKey, channelID, userID, nonce string, timestamp int64, ) (token string, err error) { var b bytes.Buffer b.WriteString(appID) b.WriteString(appKey) b.WriteString(channelID) b.WriteString(userID) b.WriteString(nonce) b.WriteString(fmt.Sprint(timestamp)) h := sha256.New() if _, err = h.Write([]byte(b.String())); err != nil { return "", err } s := h.Sum(nil) token = hex.EncodeToString(s) return } // generate a random string func BuildRandom(length int) string { if length <= 0 { return "" } b := make([]byte, length/2+1) _, _ = cr.Read(b) s := hex.EncodeToString(b) return s[:length] } // 获取rtc token,用于rtc推流与拉流服务 func GetToken(c *gin.Context) { appID := viper.GetString("rtc.appID") appKey := viper.GetString("rtc.appKey") gslb := viper.GetString("rtc.gslb") r := c.Request w := c.Writer if appID == "" || appKey == "" || gslb == "" { os.Exit(-1) } ol.Tf(nil, "appid=%v, appkey=%v, gslb=%v", appID, appKey, gslb) if o := r.Header.Get("Origin"); o != "" { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET,POST,HEAD,PUT,DELETE,OPTIONS") w.Header().Set("Access-Control-Expose-Headers", "Server,Range,Content-Length,Content-Range") w.Header().Set("Access-Control-Allow-Headers", "Origin,Range,Accept-Encoding,Referer,Cache-Control,X-Proxy-Authorization,X-Requested-With,Content-Type") } // For matched OPTIONS, should directly return without response. if r.Method == "OPTIONS" { return } q := r.URL.Query() channelID, user := q.Get("room"), q.Get("user") ol.Tf(nil, "Request channelId=%v, user=%v, appid=%v", channelID, user, appID) if channelID == "" || user == "" { oh.WriteError(nil, w, r, errors.New("invalid parameter")) return } userID := CreateUserID(channelID, user) // Warning: nonce support the AppKey generated token. // the Nonce should be prefix with 'AK-' otherwise the joining verification will failed. // eg. nonce: "AK-0464002093ce3dd010cb05356c8b1d0f". uuid := uuid.NewV4() // if err != nil { // oh.WriteError(nil, w, r, err) // return // } nonce := fmt.Sprintf("AK-%v", uuid) // Warning: timestamp is the token expiration time. // User can custom defined the expire time of token. // eg, Expires in two days. timestamp: 1559890860. timestamp := time.Now().Add(48 * time.Hour).Unix() token, err := CreateToken(appID, appKey, channelID, userID, nonce, timestamp) if err != nil { oh.WriteError(nil, w, r, err) return } username := fmt.Sprintf("%s?appid=%s&channel=%s&nonce=%s×tamp=%d", userID, appID, channelID, nonce, timestamp) ol.Tf(nil, "Login: appID=%v, appKey=%v, channelID=%v, userID=%v, nonce=%v, "+ "timestamp=%v, user=%v, userName=%v, token=%v", appID, appKey, channelID, userID, nonce, timestamp, user, username, token) type TURN struct { Username string `json:"username"` Password string `json:"password"` } type Response struct { AppId string `json:"appid"` UserId string `json:"userid"` GSLB []string `json:"gslb"` Token string `json:"token"` Nonce string `json:"nonce"` Timestamp int64 `json:"timestamp"` TURN *TURN `json:"turn"` } oh.WriteData(nil, w, r, &Response{ appID, userID, []string{gslb}, token, nonce, timestamp, &TURN{username, token}, }) data := gin.H{ "appID": appID, "userID": userID, "gslb": []string{gslb}, "token": token, "nonce": timestamp, "TURN": &TURN{username, token}, } controllers.Response(c, common.OK, "", data) }