Skip to content

Commit

Permalink
wip rework
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Nov 12, 2023
1 parent 6602034 commit c776513
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 21 deletions.
10 changes: 5 additions & 5 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@ func newHttpClient() *http.Client {

func newEchoServer(log *otelzap.Logger, pool *pgxpool.Pool, conv *service.SessionJwtConverter) *echo.Echo {
app := echo.New()
app.Use(
otelecho.Middleware("api.gw2auth.com"),
web.Middleware(log, pool),
)

authMw := web.AuthenticatedMiddleware(conv)

app.GET("/api-v2/application/summary", web.AppSummaryEndpoint())
app.GET("/api-v2/authinfo", web.AuthInfoEndpoint(), authMw)
app.GET("/api-v2/gw2account", web.Gw2AccountsEndpoint(), authMw)

app.Use(
otelecho.Middleware("api.gw2auth.com"),
web.Middleware(log, pool),
)
app.PATCH("/api-v2/gw2account/:id", web.UpdateGw2AccountEndpoint(), authMw)

return app
}
Expand Down
20 changes: 15 additions & 5 deletions service/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewSessionJwtConverter(kid string, priv *rsa.PrivateKey, pub map[string]*rs
}
}

func (c *SessionJwtConverter) ReadJWT(jwtStr string) (SessionJwtClaims, error) {
func (c *SessionJwtConverter) ReadJWT(jwtStr string) (SessionJwtClaims, time.Time, error) {
tk, err := c.parser.Parse(jwtStr, func(tk *jwt.Token) (interface{}, error) {
if m, ok := tk.Method.(*jwt.SigningMethodRSA); !ok || m != jwt.SigningMethodRS256 {
return nil, fmt.Errorf("unexpected signing method: %v", tk.Header["alg"])
Expand All @@ -69,7 +69,12 @@ func (c *SessionJwtConverter) ReadJWT(jwtStr string) (SessionJwtClaims, error) {
return nil, errors.New("expected k claim to be a non-empty string")
}

pub, ok := c.pub[tk.Header["kid"].(string)]
kid, ok := tk.Header["kid"].(string)
if !ok {
return nil, errors.New("kid header not found")
}

pub, ok := c.pub[kid]
if !ok {
return nil, errors.New("unknown kid")
}
Expand All @@ -78,19 +83,24 @@ func (c *SessionJwtConverter) ReadJWT(jwtStr string) (SessionJwtClaims, error) {
})

if err != nil {
return SessionJwtClaims{}, fmt.Errorf("failed to parse jwt: %w", err)
return SessionJwtClaims{}, time.Time{}, fmt.Errorf("failed to parse jwt: %w", err)
}

claims := tk.Claims.(jwt.MapClaims)
k, err := base64.RawStdEncoding.DecodeString(claims[encryptionKeyClaim].(string))
if err != nil {
return SessionJwtClaims{}, fmt.Errorf("k claim could not be decoded: %w", err)
return SessionJwtClaims{}, time.Time{}, fmt.Errorf("k claim could not be decoded: %w", err)
}

iat, err := tk.Claims.GetIssuedAt()
if err != nil {
return SessionJwtClaims{}, time.Time{}, fmt.Errorf("iat claim could not be read: %w", err)
}

return SessionJwtClaims{
SessionId: claims[sessionClaim].(string),
EncryptionKey: k,
}, nil
}, iat.Time, nil
}

func (c *SessionJwtConverter) WriteJWT(claims SessionJwtClaims, exp time.Time) (string, error) {
Expand Down
43 changes: 38 additions & 5 deletions service/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/gofrs/uuid/v5"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"math"
"time"
)

Expand All @@ -32,7 +33,7 @@ type PgxConn interface {
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
}

func LoadAndUpdateSession(ctx context.Context, conn PgxConn, id string, encryptionKey []byte, newMetadata SessionMetadata, sess *Session) error {
func LoadAndUpdateSession(ctx context.Context, conn PgxConn, id string, encryptionKey []byte, issuedAt time.Time, newMetadata SessionMetadata, sess *Session) error {
sql := `
SELECT
acc.id,
Expand Down Expand Up @@ -80,7 +81,7 @@ FOR UPDATE OF acc_fed_sess
return fmt.Errorf("failed to parse stored metadata: %w", err)
}

if !isMetadataPlausible(sess.Metadata, newMetadata) {
if !isMetadataPlausible(sess.Metadata, newMetadata, time.Now().Sub(issuedAt)) {
return errors.New("metadata not plausible")
}

Expand Down Expand Up @@ -115,7 +116,39 @@ func DeleteSession(ctx context.Context, conn PgxConn, id string) error {
return err
}

func isMetadataPlausible(orig SessionMetadata, current SessionMetadata) bool {
// TODO
return true
func isMetadataPlausible(orig SessionMetadata, current SessionMetadata, passed time.Duration) bool {
travelledKm := distance(orig.Lat, orig.Lng, current.Lat, current.Lng)
if travelledKm > 1000 {
// never allow to travel more than 1000km
return false
}

if travelledKm <= 30 {
// always allow to travel 30km
return true
}

return travelledKm <= (333.3 * (passed.Seconds() / 86400.0))
}

// https://gist.github.com/hotdang-ca/6c1ee75c48e515aec5bc6db6e3265e49
// value returned is distance in kilometers
func distance(lat1 float64, lng1 float64, lat2 float64, lng2 float64) float64 {
radlat1 := float64(math.Pi * lat1 / 180)
radlat2 := float64(math.Pi * lat2 / 180)

theta := float64(lng1 - lng2)
radtheta := float64(math.Pi * theta / 180)

dist := math.Sin(radlat1)*math.Sin(radlat2) + math.Cos(radlat1)*math.Cos(radlat2)*math.Cos(radtheta)
if dist > 1 {
dist = 1
}

dist = math.Acos(dist)
dist = dist * 180 / math.Pi
dist = dist * 60 * 1.1515
dist = dist * 1.609344

return dist
}
69 changes: 65 additions & 4 deletions web/gw2_accounts.go → web/gw2_account.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package web

import (
"errors"
"github.com/gofrs/uuid/v5"
"github.com/gw2auth/gw2auth.com-api/service"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
"net/http"
"time"
)
Expand Down Expand Up @@ -36,9 +38,9 @@ func Gw2AccountsEndpoint() echo.HandlerFunc {
sql := `
SELECT
gw2_acc.gw2_account_id,
gw2_acc.gw2_account_name,
gw2_acc.display_name,
gw2_acc.creation_time,
MAX(gw2_acc.gw2_account_name),
MAX(gw2_acc.display_name),
MAX(gw2_acc.creation_time),
COUNT(gw2_acc_ver.account_id) > 0,
COUNT(gw2_acc_ver_pend.account_id) > 0,
MAX(gw2_acc_tk.gw2_api_token),
Expand All @@ -57,7 +59,7 @@ LEFT JOIN application_client_authorizations app_client_auth
LEFT JOIN application_clients app_client
ON app_client_auth.application_client_id = app_client.id
WHERE gw2_acc.account_id = $1
GROUP BY gw2_acc.account_id, gw2_acc.gw2_account_id
GROUP BY gw2_acc.gw2_account_id
`
rows, err := tx.Query(ctx, sql, session.AccountId)
if err != nil {
Expand Down Expand Up @@ -103,3 +105,62 @@ GROUP BY gw2_acc.account_id, gw2_acc.gw2_account_id
return c.JSON(http.StatusOK, results)
})
}

type gw2AccountUpdate struct {
DisplayName string `json:"displayName,omitempty"`
ApiToken string `json:"apiToken,omitempty"`
}

func UpdateGw2AccountEndpoint() echo.HandlerFunc {
return wrapAuthenticatedHandlerFunc(func(c echo.Context, rctx RequestContext, session service.Session) error {
gw2AccountId, err := uuid.FromString(c.Param("id"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}

var update gw2AccountUpdate
if err = c.Bind(&update); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}

if update.DisplayName == "" && update.ApiToken == "" {
return echo.NewHTTPError(http.StatusBadRequest, errors.New("nothing to update"))
}

rctx.Log().Info(
"updating gw2account",
zap.String("accountId", session.AccountId.String()),
zap.String("gw2AccountId", gw2AccountId.String()),
zap.String("displayName", update.DisplayName),
zap.Bool("apiToken", update.ApiToken != ""),
)

ctx := c.Request().Context()
var rowsAffected int64

err = rctx.ExecuteTx(ctx, pgx.TxOptions{}, func(tx pgx.Tx) error {
sql := `
UPDATE gw2_accounts
SET display_name = $3
WHERE account_id = $1 AND gw2_account_id = $2
`
tag, err := tx.Exec(ctx, sql, session.AccountId, gw2AccountId, update.DisplayName)
if err != nil {
return err
}

rowsAffected = tag.RowsAffected()
return nil
})

if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err)
}

if rowsAffected < 1 {
return echo.NewHTTPError(http.StatusNotFound, map[string]string{})
}

return c.JSON(http.StatusOK, map[string]string{})
})
}
4 changes: 2 additions & 2 deletions web/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func AuthenticatedMiddleware(conv *service.SessionJwtConverter) echo.MiddlewareF
return ctx, onErr(c, rctx, cookie, "", err)
}

claims, err := conv.ReadJWT(cookie.Value)
claims, iat, err := conv.ReadJWT(cookie.Value)
if err != nil {
return ctx, onErr(c, rctx, cookie, "", err)
}
Expand All @@ -164,7 +164,7 @@ func AuthenticatedMiddleware(conv *service.SessionJwtConverter) echo.MiddlewareF

var session service.Session
err = rctx.ExecuteTx(ctx, pgx.TxOptions{}, func(tx pgx.Tx) error {
return service.LoadAndUpdateSession(ctx, tx, claims.SessionId, claims.EncryptionKey, sessionMetadata, &session)
return service.LoadAndUpdateSession(ctx, tx, claims.SessionId, claims.EncryptionKey, iat, sessionMetadata, &session)
})

if err != nil {
Expand Down

0 comments on commit c776513

Please sign in to comment.