Compare commits
No commits in common. "d91b3d72b347056855c96f9ba22dad7c972a556b" and "ede2da8f8dcd08f3ede98801d7df21648391b1bc" have entirely different histories.
d91b3d72b3
...
ede2da8f8d
26
CHANGELOG.md
26
CHANGELOG.md
|
|
@ -1,26 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
## [1.0.0-rc.1] - 2021-11-20
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Postgresql support for channels, feeds, items and subscriptions.
|
|
||||||
- Support "source" in items and feeds
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Default channel backend is postgresql
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- All `staticcheck` problems are fixed.
|
|
||||||
- Dependency between memorybackend and hubbackend removed and simplified.
|
|
||||||
|
|
||||||
### Deprecated
|
|
||||||
|
|
||||||
- All Redis timeline types are deprecated and will be removed in a later version.
|
|
||||||
|
|
||||||
[Unreleased]: https://git.p83.nl/peter/ekster/compare/1.0.0-rc.1...master
|
|
||||||
[1.0.0-rc.1]: https://git.p83.nl/peter/ekster/src/tag/1.0.0-rc.1
|
|
||||||
|
|
@ -242,6 +242,7 @@ func channelID(sub microsub.Microsub, channelNameOrID string) (string, error) {
|
||||||
// we encountered an error, so we are not sure if it worked
|
// we encountered an error, so we are not sure if it worked
|
||||||
return channelNameOrID, err
|
return channelNameOrID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
if c.Name == channelNameOrID {
|
if c.Name == channelNameOrID {
|
||||||
return c.UID, nil
|
return c.UID, nil
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cristalhq/jwt/v4"
|
|
||||||
"p83.nl/go/ekster/pkg/indieauth"
|
"p83.nl/go/ekster/pkg/indieauth"
|
||||||
"p83.nl/go/ekster/pkg/microsub"
|
"p83.nl/go/ekster/pkg/microsub"
|
||||||
"p83.nl/go/ekster/pkg/util"
|
"p83.nl/go/ekster/pkg/util"
|
||||||
|
|
@ -46,7 +44,7 @@ import (
|
||||||
var templates embed.FS
|
var templates embed.FS
|
||||||
|
|
||||||
type mainHandler struct {
|
type mainHandler struct {
|
||||||
Backend microsub.Microsub
|
Backend *memoryBackend
|
||||||
BaseURL string
|
BaseURL string
|
||||||
TemplateDir string
|
TemplateDir string
|
||||||
pool *redis.Pool
|
pool *redis.Pool
|
||||||
|
|
@ -113,12 +111,6 @@ type authRequest struct {
|
||||||
AccessToken string `redis:"access_token"`
|
AccessToken string `redis:"access_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type micropubClaims struct {
|
|
||||||
jwt.RegisteredClaims
|
|
||||||
Channel string
|
|
||||||
Me string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMainHandler(backend *memoryBackend, baseURL, templateDir string, pool *redis.Pool) (*mainHandler, error) {
|
func newMainHandler(backend *memoryBackend, baseURL, templateDir string, pool *redis.Pool) (*mainHandler, error) {
|
||||||
h := &mainHandler{Backend: backend}
|
h := &mainHandler{Backend: backend}
|
||||||
|
|
||||||
|
|
@ -172,13 +164,11 @@ func loadSession(sessionVar string, conn redis.Conn) (session, error) {
|
||||||
sessionKey := "session:" + sessionVar
|
sessionKey := "session:" + sessionVar
|
||||||
data, err := redis.Values(conn.Do("HGETALL", sessionKey))
|
data, err := redis.Values(conn.Do("HGETALL", sessionKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
|
||||||
return sess, err
|
return sess, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = redis.ScanStruct(data, &sess)
|
err = redis.ScanStruct(data, &sess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
|
||||||
return sess, err
|
return sess, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,19 +230,18 @@ func verifyAuthCode(code, redirectURI, authEndpoint, clientID string) (bool, *au
|
||||||
return false, nil, fmt.Errorf("unknown content-type %q while verifying authorization_code", contentType)
|
return false, nil, fmt.Errorf("unknown content-type %q while verifying authorization_code", contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isLoggedIn(sess *session) bool {
|
func isLoggedIn(backend *memoryBackend, sess *session) bool {
|
||||||
if !sess.LoggedIn {
|
if !sess.LoggedIn {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Do we need this?
|
if !backend.AuthEnabled {
|
||||||
// if !backend.AuthEnabled {
|
return true
|
||||||
// return true
|
}
|
||||||
// }
|
|
||||||
//
|
if sess.Me != backend.Me {
|
||||||
// if sess.Me != backend.Me {
|
return false
|
||||||
// return false
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -262,6 +251,7 @@ func performIndieauthCallback(clientID string, r *http.Request, sess *session) (
|
||||||
if state != sess.State {
|
if state != sess.State {
|
||||||
return false, &authResponse{}, fmt.Errorf("mismatched state")
|
return false, &authResponse{}, fmt.Errorf("mismatched state")
|
||||||
}
|
}
|
||||||
|
|
||||||
code := r.Form.Get("code")
|
code := r.Form.Get("code")
|
||||||
return verifyAuthCode(code, sess.RedirectURI, sess.AuthorizationEndpoint, clientID)
|
return verifyAuthCode(code, sess.RedirectURI, sess.AuthorizationEndpoint, clientID)
|
||||||
}
|
}
|
||||||
|
|
@ -387,7 +377,7 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isLoggedIn(&sess) {
|
if !isLoggedIn(h.Backend, &sess) {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
fmt.Fprintf(w, "Unauthorized")
|
fmt.Fprintf(w, "Unauthorized")
|
||||||
return
|
return
|
||||||
|
|
@ -412,14 +402,14 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, v := range page.Channels {
|
for _, v := range page.Channels {
|
||||||
if v.UID == currentChannel {
|
if v.UID == currentChannel {
|
||||||
page.CurrentChannel = v
|
page.CurrentChannel = v
|
||||||
// if setting, e := h.Backend.Settings[v.UID]; e {
|
if setting, e := h.Backend.Settings[v.UID]; e {
|
||||||
// page.CurrentSetting = setting
|
page.CurrentSetting = setting
|
||||||
// } else {
|
} else {
|
||||||
page.CurrentSetting = channelSetting{}
|
page.CurrentSetting = channelSetting{}
|
||||||
// }
|
}
|
||||||
// if page.CurrentSetting.ChannelType == "" {
|
if page.CurrentSetting.ChannelType == "" {
|
||||||
page.CurrentSetting.ChannelType = "postgres-stream"
|
page.CurrentSetting.ChannelType = "postgres-stream"
|
||||||
// }
|
}
|
||||||
page.ExcludedTypeNames = map[string]string{
|
page.ExcludedTypeNames = map[string]string{
|
||||||
"repost": "Reposts",
|
"repost": "Reposts",
|
||||||
"like": "Likes",
|
"like": "Likes",
|
||||||
|
|
@ -458,7 +448,7 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isLoggedIn(&sess) {
|
if !isLoggedIn(h.Backend, &sess) {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
fmt.Fprintf(w, "Unauthorized")
|
fmt.Fprintf(w, "Unauthorized")
|
||||||
return
|
return
|
||||||
|
|
@ -486,7 +476,7 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isLoggedIn(&sess) {
|
if !isLoggedIn(h.Backend, &sess) {
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
fmt.Fprintf(w, "Unauthorized")
|
fmt.Fprintf(w, "Unauthorized")
|
||||||
return
|
return
|
||||||
|
|
@ -508,39 +498,9 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else if r.URL.Path == "/auth" {
|
} else if r.URL.Path == "/auth" {
|
||||||
// check arguments for auth
|
// check if we are logged in
|
||||||
query := r.URL.Query()
|
// TODO: if not logged in, make sure we get back here
|
||||||
responseType := query.Get("response_type")
|
|
||||||
if responseType != "code" {
|
|
||||||
http.Error(w, "Unsupported response_type", 400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectURI := query.Get("redirect_uri")
|
|
||||||
if _, err := url.Parse(redirectURI); err != nil {
|
|
||||||
http.Error(w, "Missing redirect_uri", 400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clientID := query.Get("client_id")
|
|
||||||
if _, err := url.Parse(clientID); err != nil {
|
|
||||||
http.Error(w, "Missing client_id", 400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
me := query.Get("me")
|
|
||||||
if _, err := url.Parse(me); err != nil {
|
|
||||||
http.Error(w, "Missing me", 400)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
state := query.Get("state")
|
|
||||||
scope := query.Get("scope")
|
|
||||||
if scope == "" {
|
|
||||||
scope = "create"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the client is logging in
|
|
||||||
sessionVar := getSessionCookie(w, r)
|
sessionVar := getSessionCookie(w, r)
|
||||||
|
|
||||||
sess, err := loadSession(sessionVar, conn)
|
sess, err := loadSession(sessionVar, conn)
|
||||||
|
|
@ -550,7 +510,7 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isLoggedIn(&sess) {
|
if !isLoggedIn(h.Backend, &sess) {
|
||||||
sess.NextURI = r.URL.String()
|
sess.NextURI = r.URL.String()
|
||||||
saveSession(sessionVar, &sess, conn)
|
saveSession(sessionVar, &sess, conn)
|
||||||
http.Redirect(w, r, "/", http.StatusFound)
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
|
|
@ -560,6 +520,18 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
sess.NextURI = r.URL.String()
|
sess.NextURI = r.URL.String()
|
||||||
saveSession(sessionVar, &sess, conn)
|
saveSession(sessionVar, &sess, conn)
|
||||||
|
|
||||||
|
query := r.URL.Query()
|
||||||
|
|
||||||
|
// responseType := query.Get("response_type") // TODO: check response_type
|
||||||
|
me := query.Get("me")
|
||||||
|
clientID := query.Get("client_id")
|
||||||
|
redirectURI := query.Get("redirect_uri")
|
||||||
|
state := query.Get("state")
|
||||||
|
scope := query.Get("scope")
|
||||||
|
if scope == "" {
|
||||||
|
scope = "create"
|
||||||
|
}
|
||||||
|
|
||||||
authReq := authRequest{
|
authReq := authRequest{
|
||||||
Me: me,
|
Me: me,
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
|
|
@ -613,18 +585,6 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// redirect to endpoint
|
// redirect to endpoint
|
||||||
me := r.Form.Get("url")
|
me := r.Form.Get("url")
|
||||||
if !strings.HasPrefix("https://", me) {
|
|
||||||
me = fmt.Sprintf("https://%s", me)
|
|
||||||
}
|
|
||||||
meURL, err := url.Parse(me)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("Not a url: %s", me), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if meURL.Path == "" {
|
|
||||||
meURL.Path = "/"
|
|
||||||
}
|
|
||||||
me = meURL.String()
|
|
||||||
|
|
||||||
endpoints, err := getEndpoints(me)
|
endpoints, err := getEndpoints(me)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -735,31 +695,17 @@ func (h *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "ERROR: %q", err)
|
fmt.Fprintf(w, "ERROR: %q", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
token := util.RandStringBytes(32)
|
||||||
key := []byte(os.Getenv("APP_SECRET"))
|
_, err = conn.Do("HMSET", redis.Args{}.Add("token:"+token).AddFlat(&auth)...)
|
||||||
signer, err := jwt.NewSignerHS(jwt.HS256, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("could not create signer for jwt: %s", err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
fmt.Fprintf(w, "ERROR: %q", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
builder := jwt.NewBuilder(signer)
|
|
||||||
token, err := builder.Build(µpubClaims{
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
||||||
},
|
|
||||||
Channel: auth.Channel,
|
|
||||||
Me: auth.Me,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("could not create signer for jwt: %s", err)
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := authTokenResponse{
|
res := authTokenResponse{
|
||||||
Me: auth.Me,
|
Me: auth.Me,
|
||||||
AccessToken: token.String(),
|
AccessToken: token,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
Scope: auth.Scope,
|
Scope: auth.Scope,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* Ekster is a microsub server
|
|
||||||
* Copyright (c) 2021 The Ekster authors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/gomodule/redigo/redis"
|
|
||||||
"github.com/rafaeljusto/redigomock/v3"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"p83.nl/go/ekster/pkg/server"
|
|
||||||
"p83.nl/go/ekster/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rand.Seed(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMainHandler_ServeHTTP_NoArgs(t *testing.T) {
|
|
||||||
conn := redigomock.NewConn()
|
|
||||||
pool := &redis.Pool{
|
|
||||||
// Return the same connection mock for each Get() call.
|
|
||||||
Dial: func() (redis.Conn, error) { return conn, nil },
|
|
||||||
MaxIdle: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
h := mainHandler{Backend: &memoryBackend{AuthEnabled: true}, BaseURL: "", TemplateDir: "", pool: pool}
|
|
||||||
r := httptest.NewRequest(http.MethodGet, "/auth", nil)
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
assert.Equal(t, 400, w.Code)
|
|
||||||
}
|
|
||||||
func TestMainHandler_ServeHTTP_Args(t *testing.T) {
|
|
||||||
conn := redigomock.NewConn()
|
|
||||||
pool := &redis.Pool{
|
|
||||||
// Return the same connection mock for each Get() call.
|
|
||||||
Dial: func() (redis.Conn, error) { return conn, nil },
|
|
||||||
MaxIdle: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
q := url.Values{}
|
|
||||||
q.Add("response_type", "code")
|
|
||||||
q.Add("client_id", "https://example.com/")
|
|
||||||
q.Add("redirect_uri", "https://example.com/callback")
|
|
||||||
q.Add("me", "https://p83.nl/")
|
|
||||||
state := util.RandStringBytes(32)
|
|
||||||
q.Add("state", state)
|
|
||||||
q.Add("scope", "create")
|
|
||||||
h := mainHandler{Backend: &server.NullBackend{}, BaseURL: "", TemplateDir: "", pool: pool}
|
|
||||||
r := httptest.NewRequest(http.MethodGet, "/auth?"+q.Encode(), nil)
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
|
|
||||||
conn.Command("HGETALL", "session:FpLSjFbcXoEFfRsW").ExpectMap(map[string]string{
|
|
||||||
"logged_in": "1",
|
|
||||||
})
|
|
||||||
conn.Command(
|
|
||||||
"HMSET", "state:XVlBzgbaiCMRAjWwhTHctcuAxhxKQFDa",
|
|
||||||
"me", "https://p83.nl/",
|
|
||||||
"client_id", "https://example.com/",
|
|
||||||
"scope", "create",
|
|
||||||
"redirect_uri", "https://example.com/callback",
|
|
||||||
"state", "XVlBzgbaiCMRAjWwhTHctcuAxhxKQFDa",
|
|
||||||
"code", "",
|
|
||||||
"channel", "",
|
|
||||||
"access_token", "",
|
|
||||||
)
|
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
assert.Equal(t, 302, w.Code)
|
|
||||||
body, err := ioutil.ReadAll(w.Result().Body)
|
|
||||||
if assert.NoError(t, err) {
|
|
||||||
assert.Equal(t, "", string(body))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -34,8 +33,6 @@ import (
|
||||||
"github.com/gomodule/redigo/redis"
|
"github.com/gomodule/redigo/redis"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"willnorris.com/go/microformats"
|
"willnorris.com/go/microformats"
|
||||||
|
|
||||||
"github.com/cristalhq/jwt/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type micropubHandler struct {
|
type micropubHandler struct {
|
||||||
|
|
@ -186,11 +183,6 @@ func getChannelFromAuthorization(r *http.Request, conn redis.Conn) (string, erro
|
||||||
token := authHeader[7:]
|
token := authHeader[7:]
|
||||||
channel, err := redis.String(conn.Do("HGET", "token:"+token, "channel"))
|
channel, err := redis.String(conn.Do("HGET", "token:"+token, "channel"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err := verifyJWT(token)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.Wrap(err, "could not get channel for token")
|
return "", errors.Wrap(err, "could not get channel for token")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,28 +191,3 @@ func getChannelFromAuthorization(r *http.Request, conn redis.Conn) (string, erro
|
||||||
|
|
||||||
return "", fmt.Errorf("could not get channel from authorization")
|
return "", fmt.Errorf("could not get channel from authorization")
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyJWT(token string) (bool, error) {
|
|
||||||
key := []byte(os.Getenv("APP_SECRET"))
|
|
||||||
verifier, err := jwt.NewVerifierHS(jwt.HS256, key)
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("could not create verifier for jwt: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
newToken, err := jwt.Parse([]byte(token), verifier)
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("could not parse jwt: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var newClaims jwt.RegisteredClaims
|
|
||||||
err = json.Unmarshal(newToken.Claims(), &newClaims)
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("could not parse jwt claims: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !newClaims.IsValidAt(time.Now()) {
|
|
||||||
return false, fmt.Errorf("jwt is not valid now")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -5,14 +5,12 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
||||||
github.com/blevesearch/bleve/v2 v2.0.3
|
github.com/blevesearch/bleve/v2 v2.0.3
|
||||||
github.com/cristalhq/jwt/v4 v4.0.0-beta // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gilliek/go-opml v1.0.0
|
github.com/gilliek/go-opml v1.0.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.15.1
|
github.com/golang-migrate/migrate/v4 v4.15.1
|
||||||
github.com/gomodule/redigo v1.8.5
|
github.com/gomodule/redigo v1.8.2
|
||||||
github.com/lib/pq v1.10.1
|
github.com/lib/pq v1.10.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rafaeljusto/redigomock/v3 v3.0.1 // indirect
|
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
golang.org/x/net v0.0.0-20211013171255-e13a2654a71e
|
golang.org/x/net v0.0.0-20211013171255-e13a2654a71e
|
||||||
willnorris.com/go/microformats v1.1.0
|
willnorris.com/go/microformats v1.1.0
|
||||||
|
|
|
||||||
7
go.sum
7
go.sum
|
|
@ -312,8 +312,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cristalhq/jwt/v4 v4.0.0-beta h1:TSNUSW7CCvMtX+Rg3vj706BwqIEt9HMvVv6Syifq5mU=
|
|
||||||
github.com/cristalhq/jwt/v4 v4.0.0-beta/go.mod h1:HnYraSNKDRag1DZP92rYHyrjyQHnVEHPNqesmzs+miQ=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||||
|
|
@ -498,9 +496,6 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
||||||
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||||
github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
|
||||||
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
|
|
||||||
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
|
|
@ -843,8 +838,6 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
||||||
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rafaeljusto/redigomock/v3 v3.0.1 h1:AUsXTuf+UEMwVEgRHRDYFFCJ1quS2JVDQmTWypjI5mI=
|
|
||||||
github.com/rafaeljusto/redigomock/v3 v3.0.1/go.mod h1:51LNR7Q4YFsi0N+CHr7+FC1Jx2lPLzcRHCPlLO2Qbpw=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,6 @@ type Microsub interface {
|
||||||
ItemSearch(channel, query string) ([]Item, error)
|
ItemSearch(channel, query string) ([]Item, error)
|
||||||
|
|
||||||
Events() (chan sse.Message, error)
|
Events() (chan sse.Message, error)
|
||||||
RefreshFeeds()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON encodes an Unread value as JSON
|
// MarshalJSON encodes an Unread value as JSON
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,6 @@ import (
|
||||||
type NullBackend struct {
|
type NullBackend struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshFeeds refreshes feeds
|
|
||||||
func (b *NullBackend) RefreshFeeds() {
|
|
||||||
// TODO implement me
|
|
||||||
// panic("implement me")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChannelsGetList gets no channels
|
// ChannelsGetList gets no channels
|
||||||
func (b *NullBackend) ChannelsGetList() ([]microsub.Channel, error) {
|
func (b *NullBackend) ChannelsGetList() ([]microsub.Channel, error) {
|
||||||
return []microsub.Channel{
|
return []microsub.Channel{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user