From c24c2ac2d878e0b9e310e9f0d5786d98cc695b98 Mon Sep 17 00:00:00 2001 From: Lukas Heiligenbrunner Date: Tue, 9 Mar 2021 12:56:53 +0000 Subject: [PATCH] add secure requests with tokens. generate new token on every new page load --- apiGo/api/ApiBase.go | 12 +- apiGo/api/oauth/Oauth.go | 67 ++++++++ apiGo/go.mod | 6 +- apiGo/go.sum | 109 +++++++++++++ src/elements/ActorTile/ActorTile.test.js | 4 - src/setupTests.js | 16 +- src/utils/Api.ts | 193 +++++++++++++++++++++-- 7 files changed, 372 insertions(+), 35 deletions(-) create mode 100644 apiGo/api/oauth/Oauth.go diff --git a/apiGo/api/ApiBase.go b/apiGo/api/ApiBase.go index d404141..d77f086 100644 --- a/apiGo/api/ApiBase.go +++ b/apiGo/api/ApiBase.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "net/http" + "openmediacenter/apiGo/api/oauth" ) const APIPREFIX = "/api" @@ -36,10 +37,13 @@ func AddHandler(action string, apiNode int, n interface{}, h func() []byte) { } func ServerInit(port uint16) { - http.Handle(APIPREFIX+"/video", http.HandlerFunc(videoHandler)) - http.Handle(APIPREFIX+"/tags", http.HandlerFunc(tagHandler)) - http.Handle(APIPREFIX+"/settings", http.HandlerFunc(settingsHandler)) - http.Handle(APIPREFIX+"/actor", http.HandlerFunc(actorHandler)) + http.Handle(APIPREFIX+"/video", oauth.ValidateToken(videoHandler)) + http.Handle(APIPREFIX+"/tags", oauth.ValidateToken(tagHandler)) + http.Handle(APIPREFIX+"/settings", oauth.ValidateToken(settingsHandler)) + http.Handle(APIPREFIX+"/actor", oauth.ValidateToken(actorHandler)) + + // initialize oauth service and add corresponding auth routes + oauth.InitOAuth() fmt.Printf("OpenMediacenter server up and running on port %d\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) diff --git a/apiGo/api/oauth/Oauth.go b/apiGo/api/oauth/Oauth.go new file mode 100644 index 0000000..0ecacc7 --- /dev/null +++ b/apiGo/api/oauth/Oauth.go @@ -0,0 +1,67 @@ +package oauth + +import ( + "gopkg.in/oauth2.v3/errors" + "gopkg.in/oauth2.v3/manage" + "gopkg.in/oauth2.v3/models" + "gopkg.in/oauth2.v3/server" + "gopkg.in/oauth2.v3/store" + "log" + "net/http" +) + +var srv *server.Server + +func InitOAuth() { + manager := manage.NewDefaultManager() + // token store + manager.MustTokenStorage(store.NewMemoryTokenStore()) + + clientStore := store.NewClientStore() + // todo we need to check here if a password is enabled in db -- when yes set it here! + clientStore.Set("openmediacenter", &models.Client{ + ID: "openmediacenter", + Secret: "openmediacenter", + Domain: "http://localhost:8081", + }) + + manager.MapClientStorage(clientStore) + srv = server.NewServer(server.NewConfig(), manager) + srv.SetClientInfoHandler(server.ClientFormHandler) + manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg) + + srv.SetInternalErrorHandler(func(err error) (re *errors.Response) { + log.Println("Internal Error:", err.Error()) + return + }) + + srv.SetResponseErrorHandler(func(re *errors.Response) { + log.Println("Response Error:", re.Error.Error()) + }) + + http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) { + err := srv.HandleAuthorizeRequest(w, r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + }) + + http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) { + err := srv.HandleTokenRequest(w, r) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }) +} + +func ValidateToken(f http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + _, err := srv.ValidationBearerToken(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + f.ServeHTTP(w, r) + } +} diff --git a/apiGo/go.mod b/apiGo/go.mod index 3826c84..28d8db6 100644 --- a/apiGo/go.mod +++ b/apiGo/go.mod @@ -2,4 +2,8 @@ module openmediacenter/apiGo go 1.16 -require github.com/go-sql-driver/mysql v1.5.0 +require ( + github.com/go-session/session v3.1.2+incompatible + github.com/go-sql-driver/mysql v1.5.0 + gopkg.in/oauth2.v3 v3.12.0 +) diff --git a/apiGo/go.sum b/apiGo/go.sum index d314899..b0f2563 100644 --- a/apiGo/go.sum +++ b/apiGo/go.sum @@ -1,2 +1,111 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/go-session/session v3.1.2+incompatible h1:yStchEObKg4nk2F7JGE7KoFIrA/1Y078peagMWcrncg= +github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tidwall/btree v0.0.0-20170113224114-9876f1454cf0 h1:QnyrPZZvPmR0AtJCxxfCtI1qN+fYpKTKJ/5opWmZ34k= +github.com/tidwall/btree v0.0.0-20170113224114-9876f1454cf0/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= +github.com/tidwall/buntdb v1.1.0 h1:H6LzK59KiNjf1nHVPFrYj4Qnl8d8YLBsYamdL8N+Bao= +github.com/tidwall/buntdb v1.1.0/go.mod h1:Y39xhcDW10WlyYXeLgGftXVbjtM0QP+/kpz8xl9cbzE= +github.com/tidwall/gjson v1.3.2 h1:+7p3qQFaH3fOMXAJSrdZwGKcOO/lYdGS0HqGhPqDdTI= +github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e h1:+NL1GDIUOKxVfbp2KoJQD9cTQ6dyP2co9q4yzmT9FZo= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ3KKDyCkxapfufrqDqwmGjcHfAyXRrE= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/oauth2.v3 v3.12.0 h1:yOffAPoolH/i2JxwmC+pgtnY3362iPahsDpLXfDFvNg= +gopkg.in/oauth2.v3 v3.12.0/go.mod h1:XEYgKqWX095YiPT+Aw5y3tCn+7/FMnlTFKrupgSiJ3I= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/src/elements/ActorTile/ActorTile.test.js b/src/elements/ActorTile/ActorTile.test.js index 47eef82..9e8907d 100644 --- a/src/elements/ActorTile/ActorTile.test.js +++ b/src/elements/ActorTile/ActorTile.test.js @@ -12,12 +12,8 @@ describe('', function () { const func = jest.fn((_) => {}); const wrapper = shallow( func()}/>); - const func1 = jest.fn(); - prepareViewBinding(func1); - wrapper.simulate('click'); - expect(func1).toBeCalledTimes(0); expect(func).toBeCalledTimes(1); }); }); diff --git a/src/setupTests.js b/src/setupTests.js index 33c35f7..2135359 100644 --- a/src/setupTests.js +++ b/src/setupTests.js @@ -19,7 +19,8 @@ global.prepareFetchApi = (response) => { const mockJsonPromise = Promise.resolve(response); const mockFetchPromise = Promise.resolve({ json: () => mockJsonPromise, - text: () => mockJsonPromise + text: () => mockJsonPromise, + status: 200 }); return (jest.fn().mockImplementation(() => mockFetchPromise)); }; @@ -33,19 +34,6 @@ global.prepareFailingFetchApi = () => { return (jest.fn().mockImplementation(() => mockFetchPromise)); }; -/** - * prepares a viewbinding instance - * @param func a mock function to be called - */ -global.prepareViewBinding = (func) => { - GlobalInfos.getViewBinding = () => { - return { - changeRootElement: func, - returnToLastElement: func - }; - }; -}; - global.callAPIMock = (resonse) => { const helpers = require('./utils/Api'); helpers.callAPI = jest.fn().mockImplementation((_, __, func1) => {func1(resonse);}); diff --git a/src/utils/Api.ts b/src/utils/Api.ts index 23102a9..bb72ef3 100644 --- a/src/utils/Api.ts +++ b/src/utils/Api.ts @@ -43,6 +43,153 @@ interface ApiBaseRequest { [_: string]: string | number | boolean | object } +// store api token - empty if not set +let apiToken = '' + +// a callback que to be called after api token refresh +let callQue: (() => void)[] = [] +// flag to check wheter a api refresh is currently pending +let refreshInProcess = false; +// store the expire seconds of token +let expireSeconds = -1; + +interface APIToken { + access_token: string; + expires_in: number; + scope: string; + token_type: string; +} + +/** + * refresh the api token or use that one in cookie if still valid + * @param callback to be called after successful refresh + */ +export function refreshAPIToken(callback: () => void): void { + callQue.push(callback); + + // check if already is a token refresh is in process + if (refreshInProcess) { + // if yes return + return; + } else { + // if not set flat + refreshInProcess = true; + } + + // check if a cookie with token is available + const token = getTokenCookie(); + if (token !== null) { + // check if token is at least valid for the next minute + if (token.expire > (new Date().getTime() / 1000) + 60) { + apiToken = token.token; + expireSeconds = token.expire; + callback(); + console.log("token still valid...") + callFuncQue(); + return; + } + } + + const formData = new FormData(); + formData.append("grant_type", "client_credentials"); + formData.append("client_id", "openmediacenter"); + formData.append("client_secret", 'openmediacenter'); + formData.append("scope", 'all'); + + + fetch(getBackendDomain() + '/token', {method: 'POST', body: formData}) + .then((response) => response.json() + .then((result: APIToken) => { + console.log(result) + // set api token + apiToken = result.access_token; + // set expire time + expireSeconds = (new Date().getTime() / 1000) + result.expires_in; + setTokenCookie(apiToken, expireSeconds); + // call all handlers and release flag + callFuncQue(); + })); +} + +/** + * call all qued callbacks + */ +function callFuncQue(): void { + // call all pending handlers + callQue.map(func => { + return func(); + }) + // reset pending que + callQue = [] + // release flag to be able to start new refresh + refreshInProcess = false; +} + +/** + * set the cookie for the currently gotten token + * @param token token string + * @param validSec second time when the token will be invalid + */ +function setTokenCookie(token: string, validSec: number): void { + let d = new Date(); + d.setTime(validSec * 1000); + console.log("token set" + d.toUTCString()) + let expires = "expires=" + d.toUTCString(); + document.cookie = "token=" + token + ";" + expires + ";path=/"; + document.cookie = "token_expire=" + validSec + ";" + expires + ";path=/"; +} + +/** + * get all required cookies for the token + */ +function getTokenCookie(): { token: string, expire: number } | null { + const token = decodeCookie('token'); + const expireInString = decodeCookie('token_expire'); + const expireIn = parseInt(expireInString, 10) | 0; + + if (expireIn !== 0 && token !== '') { + return {token: token, expire: expireIn}; + } else { + return null + } +} + +/** + * decode a simple cookie with key specified + * @param key cookie key + */ +function decodeCookie(key: string): string { + let name = key + "="; + let decodedCookie = decodeURIComponent(document.cookie); + let ca = decodedCookie.split(';'); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1); + } + if (c.indexOf(name) === 0) { + return c.substring(name.length, c.length); + } + } + return ""; +} + +/** + * check if api token is valid -- if not request new one + * when finished call callback + * @param callback function to be called afterwards + */ +function checkAPITokenValid(callback: () => void): void { + // check if token is valid and set + if (apiToken === '' || expireSeconds <= new Date().getTime() / 1000) { + refreshAPIToken(() => { + callback() + }) + } else { + callback() + } +} + /** * A backend api call * @param apinode which api backend handler to call @@ -50,12 +197,28 @@ interface ApiBaseRequest { * @param callback the callback with json reply from backend * @param errorcallback a optional callback if an error occured */ -export function callAPI(apinode: APINode, fd: ApiBaseRequest, callback: (_: T) => void, errorcallback: (_: string) => void = (_: string): void => {}): void { - fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd)}) - .then((response) => response.json() - .then((result) => { - callback(result); - })).catch(reason => errorcallback(reason)); +export function callAPI(apinode: APINode, + fd: ApiBaseRequest, + callback: (_: T) => void, + errorcallback: (_: string) => void = (_: string): void => { + }): void { + checkAPITokenValid(() => { + fetch(getAPIDomain() + apinode, { + method: 'POST', body: JSON.stringify(fd), headers: new Headers({ + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + apiToken, + }), + }).then((response) => { + if (response.status !== 200) { + console.log('Error: ' + response.statusText); + // todo place error popup here + } else { + response.json().then((result: T) => { + callback(result); + }) + } + }).catch(reason => errorcallback(reason)); + }) } /** @@ -65,12 +228,18 @@ export function callAPI(apinode: APINode, fd: ApiBaseRequest, callback: (_: T * @param callback the callback with PLAIN text reply from backend */ export function callAPIPlain(apinode: APINode, fd: ApiBaseRequest, callback: (_: string) => void): void { - fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd)}) - .then((response) => response.text() - .then((result) => { - callback(result); - })); - + checkAPITokenValid(() => { + fetch(getAPIDomain() + apinode, { + method: 'POST', body: JSON.stringify(fd), headers: new Headers({ + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + apiToken, + }) + }) + .then((response) => response.text() + .then((result) => { + callback(result); + })); + }); } /**