Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Make api/auth more suitable to be used as a dependency #256

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,5 @@ rMAPI will set the exit code to `0` if the command succeedes, or `1` if it fails
- `RMAPI_THUMBNAILS`: generate a thumbnail of the first page of a pdf document
- `RMAPI_AUTH`: override the default authorization url
- `RMAPI_DOC`: override the default document storage url
- `RMAPI_HOST`: override all urls
- `RMAPI_HOST`: override all urls
- `RMAPI_DEVICE_CODE`: one-time code for non-interactive usage
37 changes: 33 additions & 4 deletions api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"fmt"
"os"
"strings"
"time"

"github.com/golang-jwt/jwt"
"github.com/juruen/rmapi/config"
"github.com/juruen/rmapi/log"
"github.com/juruen/rmapi/model"
Expand All @@ -23,13 +25,20 @@ func AuthHttpCtx(reAuth, nonInteractive bool) *transport.HttpClientCtx {
httpClientCtx := transport.CreateHttpClientCtx(authTokens)

if authTokens.DeviceToken == "" {
var oneTimeCode string
if nonInteractive {
log.Error.Fatal("missing token, not asking, aborting")
if code, ok := os.LookupEnv("RMAPI_DEVICE_CODE"); ok && len(code) == 8 {
oneTimeCode = code
} else {
log.Error.Fatal("missing token, not asking, aborting")
}
} else {
oneTimeCode = readCode()
}
deviceToken, err := newDeviceToken(&httpClientCtx, readCode())

deviceToken, err := newDeviceToken(&httpClientCtx, oneTimeCode)
if err != nil {
log.Error.Fatal("failed to crete device token from on-time code")
log.Error.Fatal("failed to create device token from on-time code")
}

log.Trace.Println("device token", deviceToken)
Expand All @@ -40,7 +49,7 @@ func AuthHttpCtx(reAuth, nonInteractive bool) *transport.HttpClientCtx {
config.SaveTokens(configPath, authTokens)
}

if authTokens.UserToken == "" || reAuth {
if authTokens.UserToken == "" || reAuth || userTokenExpires(authTokens.UserToken) {
userToken, err := newUserToken(&httpClientCtx)

if err == transport.UnAuthorizedError {
Expand Down Expand Up @@ -77,6 +86,26 @@ func readCode() string {
return code
}

func userTokenExpires(token string) bool {
// if there are parsing errors or the registered claim 'exp' is missing/invalid, consider the token to be expired
// TODO: check if the v1 API JWT's contain the exp claim... if not, return false for the above mentioned cases
p := jwt.Parser{}
res, _, err := p.ParseUnverified(token, jwt.MapClaims{})
if err != nil {
return true
}
claims := res.Claims.(jwt.MapClaims)
if _, ok := claims["exp"]; !ok {
return true
}
exp := time.Unix(int64(claims["exp"].(float64)), 0).UTC()
// add 1 hour to the actual time, assuming the max. session duration of AuthHttpCtx is 1 hour...
if time.Now().UTC().Add(time.Hour).After(exp) {
return true
}
return false
}

func newDeviceToken(http *transport.HttpClientCtx, code string) (string, error) {
uuid, err := uuid.NewV4()

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/stretchr/testify v1.5.1
github.com/unidoc/unipdf/v3 v3.6.1
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.8
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
Expand Down