Skip to content
Snippets Groups Projects
Verified Commit 9c6eca4b authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

feat: token refresh

parent 890e7bd3
No related branches found
No related tags found
No related merge requests found
Pipeline #3033 passed
...@@ -5,7 +5,7 @@ import ( ...@@ -5,7 +5,7 @@ import (
"net/http" "net/http"
) )
func JoinRoom(userData LoginResponse, roomId string) error { func JoinRoom(token Token, roomId string) error {
request, err := http.NewRequest( request, err := http.NewRequest(
http.MethodPost, http.MethodPost,
fmt.Sprintf("https://matrix-client.matrix.org/_matrix/client/v3/rooms/%s/join", roomId), fmt.Sprintf("https://matrix-client.matrix.org/_matrix/client/v3/rooms/%s/join", roomId),
...@@ -14,7 +14,7 @@ func JoinRoom(userData LoginResponse, roomId string) error { ...@@ -14,7 +14,7 @@ func JoinRoom(userData LoginResponse, roomId string) error {
if err != nil { if err != nil {
panic(err) panic(err)
} }
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", userData.AccessToken)) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.AccessToken))
_, err = http.DefaultClient.Do(request) _, err = http.DefaultClient.Do(request)
return err return err
} }
...@@ -15,7 +15,7 @@ type ReadReceiptRequest struct { ...@@ -15,7 +15,7 @@ type ReadReceiptRequest struct {
ReadPrivate string `json:"m.read.private"` ReadPrivate string `json:"m.read.private"`
} }
func SetReadReceipt(userData LoginResponse, roomId string, messageId string) error { func SetReadReceipt(token Token, roomId string, messageId string) error {
body, err := json.Marshal(ReadReceiptRequest{ body, err := json.Marshal(ReadReceiptRequest{
FullyRead: messageId, FullyRead: messageId,
Read: messageId, Read: messageId,
...@@ -32,7 +32,7 @@ func SetReadReceipt(userData LoginResponse, roomId string, messageId string) err ...@@ -32,7 +32,7 @@ func SetReadReceipt(userData LoginResponse, roomId string, messageId string) err
if err != nil { if err != nil {
panic(err) panic(err)
} }
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", userData.AccessToken)) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.AccessToken))
response, err := http.DefaultClient.Do(request) response, err := http.DefaultClient.Do(request)
if err != nil { if err != nil {
return err return err
......
package api
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type RefreshRequest struct {
RefreshToken string `json:"refresh_token"`
}
type RefreshResponse struct {
AccessToken string `json:"access_token"`
ExpiresInMs int `json:"expires_in_ms"`
RefreshToken string `json:"refresh_token"`
}
func Refresh(refreshToken string) (RefreshResponse, error) {
body, err := json.Marshal(RefreshRequest{
RefreshToken: refreshToken,
})
if err != nil {
return RefreshResponse{}, err
}
resp, err := http.Post("https://matrix-client.matrix.org/_matrix/client/v3/refresh", "application/json", bytes.NewReader(body))
if err != nil {
return RefreshResponse{}, err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return RefreshResponse{}, fmt.Errorf("request failed %d: %s", resp.StatusCode, resp.Status)
}
var responseBody RefreshResponse
err = json.NewDecoder(resp.Body).Decode(&responseBody)
return responseBody, err
}
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
"net/http" "net/http"
) )
func SendMessage(userData LoginResponse, roomId string, content interface{}) error { func SendMessage(token Token, roomId string, content interface{}) error {
transactionId, err := uuid.NewRandom() transactionId, err := uuid.NewRandom()
if err != nil { if err != nil {
return err return err
...@@ -29,7 +29,7 @@ func SendMessage(userData LoginResponse, roomId string, content interface{}) err ...@@ -29,7 +29,7 @@ func SendMessage(userData LoginResponse, roomId string, content interface{}) err
if err != nil { if err != nil {
panic(err) panic(err)
} }
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", userData.AccessToken)) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.AccessToken))
response, err := http.DefaultClient.Do(request) response, err := http.DefaultClient.Do(request)
if err != nil { if err != nil {
return err return err
......
...@@ -26,7 +26,7 @@ type PusherData struct { ...@@ -26,7 +26,7 @@ type PusherData struct {
Url string `json:"url"` Url string `json:"url"`
} }
func SetPusher(userData LoginResponse, url string) error { func SetPusher(token Token, url string) error {
body, err := json.Marshal(PusherRequest{ body, err := json.Marshal(PusherRequest{
AppDisplayName: "webhook", AppDisplayName: "webhook",
AppId: "de.justjanne.webhook", AppId: "de.justjanne.webhook",
...@@ -52,7 +52,7 @@ func SetPusher(userData LoginResponse, url string) error { ...@@ -52,7 +52,7 @@ func SetPusher(userData LoginResponse, url string) error {
if err != nil { if err != nil {
panic(err) panic(err)
} }
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", userData.AccessToken)) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.AccessToken))
response, err := http.DefaultClient.Do(request) response, err := http.DefaultClient.Do(request)
if err != nil { if err != nil {
return err return err
......
package api
import "time"
type Token struct {
AccessToken string
Expires time.Time
RefreshToken string
}
...@@ -13,15 +13,11 @@ import ( ...@@ -13,15 +13,11 @@ import (
) )
func main() { func main() {
bot, err := NewMatrixBot( var err error
os.Getenv("BOT_USERNAME"),
os.Getenv("BOT_PASSWORD"), bot := NewMatrixBot()
os.Getenv("BOT_DEVICEID"),
os.Getenv("BOT_PUSHURL"), // !8ball handler
)
if err != nil {
panic(err)
}
bot.HandleFunc("!8ball", func(bot *MatrixBot, notification api.Notification) error { bot.HandleFunc("!8ball", func(bot *MatrixBot, notification api.Notification) error {
positive := []string{ positive := []string{
"It is certain", "It is certain",
...@@ -64,12 +60,14 @@ func main() { ...@@ -64,12 +60,14 @@ func main() {
} }
answer := answers[rand.IntN(len(answers))] answer := answers[rand.IntN(len(answers))]
err = api.SendMessage(bot.userData, notification.RoomId, api.MessageContent{ err = api.SendMessage(*bot.token, notification.RoomId, api.MessageContent{
Body: answer, Body: answer,
MsgType: "m.text", MsgType: "m.text",
}) })
return nil return nil
}) })
// !trains handler
bahnTpl, err := template.New("bahn").Parse(`{{- /*gotype: bahn.Timetable*/ -}} bahnTpl, err := template.New("bahn").Parse(`{{- /*gotype: bahn.Timetable*/ -}}
<b>{{.Station}}</b> Abfahrten <b>{{.Station}}</b> Abfahrten
{{- range .Stops -}} {{- range .Stops -}}
...@@ -103,12 +101,20 @@ func main() { ...@@ -103,12 +101,20 @@ func main() {
if err != nil { if err != nil {
return err return err
} }
err = api.SendMessage(bot.userData, notification.RoomId, api.MessageContent{ err = api.SendMessage(*bot.token, notification.RoomId, api.MessageContent{
FormattedBody: buf.String(), FormattedBody: buf.String(),
Format: "org.matrix.custom.html", Format: "org.matrix.custom.html",
MsgType: "m.text", MsgType: "m.text",
}) })
return nil return nil
}) })
err = bot.Login(os.Getenv("BOT_USERNAME"), os.Getenv("BOT_PASSWORD"), os.Getenv("BOT_DEVICEID"))
if err != nil {
panic(err)
}
err = bot.RegisterPusher(os.Getenv("BOT_PUSHURL"))
if err != nil {
panic(err)
}
bot.Serve(":8080") bot.Serve(":8080")
} }
package main package main
import ( import (
"fmt"
"git.kuschku.de/justjanne/stateless-matrix-bot/api" "git.kuschku.de/justjanne/stateless-matrix-bot/api"
"io" "io"
"log" "log"
"net/http" "net/http"
"strings" "strings"
"time"
) )
type MatrixBot struct { type MatrixBot struct {
userData api.LoginResponse token *api.Token
handlers map[string]func(bot *MatrixBot, notification api.Notification) error handlers map[string]func(bot *MatrixBot, notification api.Notification) error
} }
func NewMatrixBot( func NewMatrixBot() *MatrixBot {
username string, return &MatrixBot{
password string, token: nil,
deviceId string, handlers: make(map[string]func(bot *MatrixBot, notification api.Notification) error),
url string, }
) (*MatrixBot, error) { }
userData, err := api.Login(username, password, deviceId)
func (bot *MatrixBot) RefreshToken() error {
if bot.token == nil {
return fmt.Errorf("no refresh token available")
}
userData, err := api.Refresh(bot.token.RefreshToken)
if err != nil { if err != nil {
return nil, err return err
}
bot.token = &api.Token{
AccessToken: userData.AccessToken,
Expires: time.Now().Add(time.Duration(userData.ExpiresInMs) / 2 * time.Millisecond),
RefreshToken: userData.RefreshToken,
} }
err = api.SetPusher(userData, url) return nil
}
func (bot *MatrixBot) Login(username string, password string, deviceId string) error {
userData, err := api.Login(username, password, deviceId)
if err != nil { if err != nil {
return nil, err return err
} }
return &MatrixBot{ bot.token = &api.Token{
userData: userData, AccessToken: userData.AccessToken,
handlers: make(map[string]func(bot *MatrixBot, notification api.Notification) error), Expires: time.Now().Add(time.Duration(userData.ExpiresInMs) / 2 * time.Millisecond),
}, nil RefreshToken: userData.RefreshToken,
}
return nil
}
func (bot *MatrixBot) RefreshTask() {
for true {
if bot.token != nil && time.Now().After(bot.token.Expires) {
if err := bot.RefreshToken(); err != nil {
log.Printf("error refresh token: %s\n", err.Error())
}
}
time.Sleep(1 * time.Second)
}
}
func (bot *MatrixBot) RegisterPusher(url string) error {
return api.SetPusher(*bot.token, url)
} }
func (bot *MatrixBot) HandleFunc(command string, handler func(bot *MatrixBot, notification api.Notification) error) { func (bot *MatrixBot) HandleFunc(command string, handler func(bot *MatrixBot, notification api.Notification) error) {
...@@ -39,7 +72,7 @@ func (bot *MatrixBot) HandleFunc(command string, handler func(bot *MatrixBot, no ...@@ -39,7 +72,7 @@ func (bot *MatrixBot) HandleFunc(command string, handler func(bot *MatrixBot, no
func (bot *MatrixBot) Serve(endpoint string) { func (bot *MatrixBot) Serve(endpoint string) {
http.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) { http.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) {
io.WriteString(writer, "OK\n") _, _ = io.WriteString(writer, "OK\n")
}) })
http.HandleFunc("/_matrix/push/v1/notify", func(writer http.ResponseWriter, request *http.Request) { http.HandleFunc("/_matrix/push/v1/notify", func(writer http.ResponseWriter, request *http.Request) {
notification, err := api.ParseNotification(request.Body) notification, err := api.ParseNotification(request.Body)
...@@ -50,7 +83,7 @@ func (bot *MatrixBot) Serve(endpoint string) { ...@@ -50,7 +83,7 @@ func (bot *MatrixBot) Serve(endpoint string) {
if notification.EventId == "" { if notification.EventId == "" {
return return
} }
err = api.SetReadReceipt(bot.userData, notification.RoomId, notification.EventId) err = api.SetReadReceipt(*bot.token, notification.RoomId, notification.EventId)
if err != nil { if err != nil {
log.Println(err.Error()) log.Println(err.Error())
return return
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment