mirror of
https://github.com/usememos/memos.git
synced 2024-12-25 04:13:07 +03:00
refactor: migrate auth routes to v1 package (#1841)
* feat: add api v1 packages * chore: migrate auth to v1 * chore: update test
This commit is contained in:
parent
f1d85eeaec
commit
4ed9a3a0ea
17
api/auth.go
17
api/auth.go
@ -1,17 +0,0 @@
|
||||
package api
|
||||
|
||||
type SignIn struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type SSOSignIn struct {
|
||||
IdentityProviderID int `json:"identityProviderId"`
|
||||
Code string `json:"code"`
|
||||
RedirectURI string `json:"redirectUri"`
|
||||
}
|
||||
|
||||
type SignUp struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package server
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -6,21 +6,37 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/usememos/memos/api"
|
||||
"github.com/usememos/memos/common"
|
||||
"github.com/usememos/memos/plugin/idp"
|
||||
"github.com/usememos/memos/plugin/idp/oauth2"
|
||||
"github.com/usememos/memos/server/auth"
|
||||
"github.com/usememos/memos/store"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (s *Server) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
type SignIn struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type SSOSignIn struct {
|
||||
IdentityProviderID int `json:"identityProviderId"`
|
||||
Code string `json:"code"`
|
||||
RedirectURI string `json:"redirectUri"`
|
||||
}
|
||||
|
||||
type SignUp struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
g.POST("/auth/signin", func(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
signin := &api.SignIn{}
|
||||
signin := &SignIn{}
|
||||
if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signin request").SetInternal(err)
|
||||
}
|
||||
@ -44,18 +60,18 @@ func (s *Server) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Incorrect login credentials, please try again")
|
||||
}
|
||||
|
||||
if err := GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
if err := auth.GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate tokens").SetInternal(err)
|
||||
}
|
||||
if err := s.createUserAuthSignInActivity(c, user); err != nil {
|
||||
if err := s.createAuthSignInActivity(c, user); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err)
|
||||
}
|
||||
return c.JSON(http.StatusOK, composeResponse(user))
|
||||
return c.JSON(http.StatusOK, user)
|
||||
})
|
||||
|
||||
g.POST("/auth/signin/sso", func(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
signin := &api.SSOSignIn{}
|
||||
signin := &SSOSignIn{}
|
||||
if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signin request").SetInternal(err)
|
||||
}
|
||||
@ -128,18 +144,18 @@ func (s *Server) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with username %s", userInfo.Identifier))
|
||||
}
|
||||
|
||||
if err := GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
if err := auth.GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate tokens").SetInternal(err)
|
||||
}
|
||||
if err := s.createUserAuthSignInActivity(c, user); err != nil {
|
||||
if err := s.createAuthSignInActivity(c, user); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err)
|
||||
}
|
||||
return c.JSON(http.StatusOK, composeResponse(user))
|
||||
return c.JSON(http.StatusOK, user)
|
||||
})
|
||||
|
||||
g.POST("/auth/signup", func(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
signup := &api.SignUp{}
|
||||
signup := &SignUp{}
|
||||
if err := json.NewDecoder(c.Request().Body).Decode(signup); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signup request").SetInternal(err)
|
||||
}
|
||||
@ -196,23 +212,23 @@ func (s *Server) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err)
|
||||
}
|
||||
if err := GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
if err := auth.GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate tokens").SetInternal(err)
|
||||
}
|
||||
if err := s.createUserAuthSignUpActivity(c, user); err != nil {
|
||||
if err := s.createAuthSignUpActivity(c, user); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, composeResponse(user))
|
||||
return c.JSON(http.StatusOK, user)
|
||||
})
|
||||
|
||||
g.POST("/auth/signout", func(c echo.Context) error {
|
||||
RemoveTokensAndCookies(c)
|
||||
auth.RemoveTokensAndCookies(c)
|
||||
return c.JSON(http.StatusOK, true)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) createUserAuthSignInActivity(c echo.Context, user *api.User) error {
|
||||
func (s *APIV1Service) createAuthSignInActivity(c echo.Context, user *api.User) error {
|
||||
ctx := c.Request().Context()
|
||||
payload := api.ActivityUserAuthSignInPayload{
|
||||
UserID: user.ID,
|
||||
@ -234,7 +250,7 @@ func (s *Server) createUserAuthSignInActivity(c echo.Context, user *api.User) er
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) createUserAuthSignUpActivity(c echo.Context, user *api.User) error {
|
||||
func (s *APIV1Service) createAuthSignUpActivity(c echo.Context, user *api.User) error {
|
||||
ctx := c.Request().Context()
|
||||
payload := api.ActivityUserAuthSignUpPayload{
|
||||
Username: user.Username,
|
9
api/v1/test.go
Normal file
9
api/v1/test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package v1
|
||||
|
||||
import "github.com/labstack/echo/v4"
|
||||
|
||||
func (*APIV1Service) registerTestRoutes(g *echo.Group) {
|
||||
g.GET("/test", func(c echo.Context) error {
|
||||
return c.String(200, "Hello World")
|
||||
})
|
||||
}
|
27
api/v1/v1.go
Normal file
27
api/v1/v1.go
Normal file
@ -0,0 +1,27 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/usememos/memos/server/profile"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
type APIV1Service struct {
|
||||
Secret string
|
||||
Profile *profile.Profile
|
||||
Store *store.Store
|
||||
}
|
||||
|
||||
func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store) *APIV1Service {
|
||||
return &APIV1Service{
|
||||
Secret: secret,
|
||||
Profile: profile,
|
||||
Store: store,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *APIV1Service) Register(e *echo.Echo) {
|
||||
apiV1Group := e.Group("/api/v1")
|
||||
s.registerTestRoutes(apiV1Group)
|
||||
s.registerAuthRoutes(apiV1Group, s.Secret)
|
||||
}
|
10
cmd/memos.go
10
cmd/memos.go
@ -41,7 +41,15 @@ var (
|
||||
Short: `An open-source, self-hosted memo hub with knowledge management and social networking.`,
|
||||
Run: func(_cmd *cobra.Command, _args []string) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
s, err := server.NewServer(ctx, profile)
|
||||
db := db.NewDB(profile)
|
||||
if err := db.Open(ctx); err != nil {
|
||||
cancel()
|
||||
fmt.Printf("failed to open db, error: %+v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
store := store.New(db.DBInstance, profile)
|
||||
s, err := server.NewServer(ctx, profile, store)
|
||||
if err != nil {
|
||||
cancel()
|
||||
fmt.Printf("failed to create server, error: %+v\n", err)
|
||||
|
@ -1,10 +1,14 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/usememos/memos/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -59,6 +63,48 @@ func GenerateRefreshToken(userName string, userID int, secret string) (string, e
|
||||
return generateToken(userName, userID, RefreshTokenAudienceName, expirationTime, []byte(secret))
|
||||
}
|
||||
|
||||
// GenerateTokensAndSetCookies generates jwt token and saves it to the http-only cookie.
|
||||
func GenerateTokensAndSetCookies(c echo.Context, user *api.User, secret string) error {
|
||||
accessToken, err := GenerateAccessToken(user.Username, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate access token")
|
||||
}
|
||||
|
||||
cookieExp := time.Now().Add(CookieExpDuration)
|
||||
setTokenCookie(c, AccessTokenCookieName, accessToken, cookieExp)
|
||||
|
||||
// We generate here a new refresh token and saving it to the cookie.
|
||||
refreshToken, err := GenerateRefreshToken(user.Username, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate refresh token")
|
||||
}
|
||||
setTokenCookie(c, RefreshTokenCookieName, refreshToken, cookieExp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTokensAndCookies removes the jwt token and refresh token from the cookies.
|
||||
func RemoveTokensAndCookies(c echo.Context) {
|
||||
// We set the expiration time to the past, so that the cookie will be removed.
|
||||
cookieExp := time.Now().Add(-1 * time.Hour)
|
||||
setTokenCookie(c, AccessTokenCookieName, "", cookieExp)
|
||||
setTokenCookie(c, RefreshTokenCookieName, "", cookieExp)
|
||||
}
|
||||
|
||||
// setTokenCookie sets the token to the cookie.
|
||||
func setTokenCookie(c echo.Context, name, token string, expiration time.Time) {
|
||||
cookie := new(http.Cookie)
|
||||
cookie.Name = name
|
||||
cookie.Value = token
|
||||
cookie.Expires = expiration
|
||||
cookie.Path = "/"
|
||||
// Http-only helps mitigate the risk of client side script accessing the protected cookie.
|
||||
cookie.HttpOnly = true
|
||||
cookie.SameSite = http.SameSiteStrictMode
|
||||
c.SetCookie(cookie)
|
||||
}
|
||||
|
||||
// generateToken generates a jwt token.
|
||||
func generateToken(username string, userID int, aud string, expirationTime time.Time, secret []byte) (string, error) {
|
||||
// Create the JWT claims, which includes the username and expiry time.
|
||||
claims := &claimsMessage{
|
||||
|
@ -27,12 +27,12 @@ func defaultAPIRequestSkipper(c echo.Context) bool {
|
||||
return common.HasPrefixes(path, "/api")
|
||||
}
|
||||
|
||||
func (server *Server) defaultAuthSkipper(c echo.Context) bool {
|
||||
func (s *Server) defaultAuthSkipper(c echo.Context) bool {
|
||||
ctx := c.Request().Context()
|
||||
path := c.Path()
|
||||
|
||||
// Skip auth.
|
||||
if common.HasPrefixes(path, "/api/auth") {
|
||||
if common.HasPrefixes(path, "/api/v1/auth") {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ func (server *Server) defaultAuthSkipper(c echo.Context) bool {
|
||||
userFind := &api.UserFind{
|
||||
OpenID: &openID,
|
||||
}
|
||||
user, err := server.Store.FindUser(ctx, userFind)
|
||||
user, err := s.Store.FindUser(ctx, userFind)
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return false
|
||||
}
|
||||
|
@ -33,47 +33,6 @@ func getUserIDContextKey() string {
|
||||
return userIDContextKey
|
||||
}
|
||||
|
||||
// GenerateTokensAndSetCookies generates jwt token and saves it to the http-only cookie.
|
||||
func GenerateTokensAndSetCookies(c echo.Context, user *api.User, secret string) error {
|
||||
accessToken, err := auth.GenerateAccessToken(user.Username, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate access token")
|
||||
}
|
||||
|
||||
cookieExp := time.Now().Add(auth.CookieExpDuration)
|
||||
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
|
||||
|
||||
// We generate here a new refresh token and saving it to the cookie.
|
||||
refreshToken, err := auth.GenerateRefreshToken(user.Username, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate refresh token")
|
||||
}
|
||||
setTokenCookie(c, auth.RefreshTokenCookieName, refreshToken, cookieExp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTokensAndCookies removes the jwt token and refresh token from the cookies.
|
||||
func RemoveTokensAndCookies(c echo.Context) {
|
||||
// We set the expiration time to the past, so that the cookie will be removed.
|
||||
cookieExp := time.Now().Add(-1 * time.Hour)
|
||||
setTokenCookie(c, auth.AccessTokenCookieName, "", cookieExp)
|
||||
setTokenCookie(c, auth.RefreshTokenCookieName, "", cookieExp)
|
||||
}
|
||||
|
||||
// Here we are creating a new cookie, which will store the valid JWT token.
|
||||
func setTokenCookie(c echo.Context, name, token string, expiration time.Time) {
|
||||
cookie := new(http.Cookie)
|
||||
cookie.Name = name
|
||||
cookie.Value = token
|
||||
cookie.Expires = expiration
|
||||
cookie.Path = "/"
|
||||
// Http-only helps mitigate the risk of client side script accessing the protected cookie.
|
||||
cookie.HttpOnly = true
|
||||
cookie.SameSite = http.SameSiteStrictMode
|
||||
c.SetCookie(cookie)
|
||||
}
|
||||
|
||||
func extractTokenFromHeader(c echo.Context) (string, error) {
|
||||
authHeader := c.Request().Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
@ -101,6 +60,15 @@ func findAccessToken(c echo.Context) string {
|
||||
return accessToken
|
||||
}
|
||||
|
||||
func audienceContains(audience jwt.ClaimStrings, token string) bool {
|
||||
for _, v := range audience {
|
||||
if v == token {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// JWTMiddleware validates the access token.
|
||||
// If the access token is about to expire or has expired and the request has a valid refresh token, it
|
||||
// will try to generate new access token and refresh token.
|
||||
@ -226,7 +194,7 @@ func JWTMiddleware(server *Server, next echo.HandlerFunc, secret string) echo.Ha
|
||||
|
||||
// If we have a valid refresh token, we will generate new access token and refresh token
|
||||
if refreshToken != nil && refreshToken.Valid {
|
||||
if err := GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
if err := auth.GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Server error to refresh expired token. User Id %d", userID)).SetInternal(err)
|
||||
}
|
||||
}
|
||||
@ -246,12 +214,3 @@ func JWTMiddleware(server *Server, next echo.HandlerFunc, secret string) echo.Ha
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
func audienceContains(audience jwt.ClaimStrings, token string) bool {
|
||||
for _, v := range audience {
|
||||
if v == token {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -2,53 +2,45 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/usememos/memos/api"
|
||||
apiV1 "github.com/usememos/memos/api/v1"
|
||||
"github.com/usememos/memos/plugin/telegram"
|
||||
"github.com/usememos/memos/server/profile"
|
||||
"github.com/usememos/memos/store"
|
||||
"github.com/usememos/memos/store/db"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
e *echo.Echo
|
||||
db *sql.DB
|
||||
e *echo.Echo
|
||||
|
||||
ID string
|
||||
Secret string
|
||||
Profile *profile.Profile
|
||||
Store *store.Store
|
||||
|
||||
telegramBot *telegram.Bot
|
||||
}
|
||||
|
||||
func NewServer(ctx context.Context, profile *profile.Profile) (*Server, error) {
|
||||
func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
|
||||
e := echo.New()
|
||||
e.Debug = true
|
||||
e.HideBanner = true
|
||||
e.HidePort = true
|
||||
|
||||
db := db.NewDB(profile)
|
||||
if err := db.Open(ctx); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot open db")
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
e: e,
|
||||
db: db.DBInstance,
|
||||
Store: store,
|
||||
Profile: profile,
|
||||
}
|
||||
storeInstance := store.New(db.DBInstance, profile)
|
||||
s.Store = storeInstance
|
||||
|
||||
telegramBotHandler := newTelegramHandler(storeInstance)
|
||||
telegramBotHandler := newTelegramHandler(store)
|
||||
s.telegramBot = telegram.NewBotWithHandler(telegramBotHandler)
|
||||
|
||||
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||
@ -89,23 +81,23 @@ func NewServer(ctx context.Context, profile *profile.Profile) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
s.Secret = secret
|
||||
|
||||
rootGroup := e.Group("")
|
||||
s.registerRSSRoutes(rootGroup)
|
||||
|
||||
publicGroup := e.Group("/o")
|
||||
publicGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return JWTMiddleware(s, next, secret)
|
||||
return JWTMiddleware(s, next, s.Secret)
|
||||
})
|
||||
registerGetterPublicRoutes(publicGroup)
|
||||
s.registerResourcePublicRoutes(publicGroup)
|
||||
|
||||
apiGroup := e.Group("/api")
|
||||
apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return JWTMiddleware(s, next, secret)
|
||||
return JWTMiddleware(s, next, s.Secret)
|
||||
})
|
||||
s.registerSystemRoutes(apiGroup)
|
||||
s.registerAuthRoutes(apiGroup, secret)
|
||||
s.registerUserRoutes(apiGroup)
|
||||
s.registerMemoRoutes(apiGroup)
|
||||
s.registerMemoResourceRoutes(apiGroup)
|
||||
@ -117,6 +109,9 @@ func NewServer(ctx context.Context, profile *profile.Profile) (*Server, error) {
|
||||
s.registerOpenAIRoutes(apiGroup)
|
||||
s.registerMemoRelationRoutes(apiGroup)
|
||||
|
||||
apiV1Service := apiV1.NewAPIV1Service(s.Secret, profile, store)
|
||||
apiV1Service.Register(e)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@ -140,7 +135,7 @@ func (s *Server) Shutdown(ctx context.Context) {
|
||||
}
|
||||
|
||||
// Close database connection
|
||||
if err := s.db.Close(); err != nil {
|
||||
if err := s.Store.GetDB().Close(); err != nil {
|
||||
fmt.Printf("failed to close database, error: %v\n", err)
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,10 @@ func New(db *sql.DB, profile *profile.Profile) *Store {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) GetDB() *sql.DB {
|
||||
return s.db
|
||||
}
|
||||
|
||||
func (s *Store) Vacuum(ctx context.Context) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/usememos/memos/api"
|
||||
apiv1 "github.com/usememos/memos/api/v1"
|
||||
)
|
||||
|
||||
func TestAuthServer(t *testing.T) {
|
||||
@ -17,7 +18,7 @@ func TestAuthServer(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown(ctx)
|
||||
|
||||
signup := &api.SignUp{
|
||||
signup := &apiv1.SignUp{
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
@ -26,15 +27,15 @@ func TestAuthServer(t *testing.T) {
|
||||
require.Equal(t, signup.Username, user.Username)
|
||||
}
|
||||
|
||||
func (s *TestingServer) postAuthSignup(signup *api.SignUp) (*api.User, error) {
|
||||
func (s *TestingServer) postAuthSignup(signup *apiv1.SignUp) (*api.User, error) {
|
||||
rawData, err := json.Marshal(&signup)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal signup")
|
||||
}
|
||||
reader := bytes.NewReader(rawData)
|
||||
body, err := s.post("/api/auth/signup", reader, nil)
|
||||
body, err := s.post("/api/v1/auth/signup", reader, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fail to post request")
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
@ -43,12 +44,9 @@ func (s *TestingServer) postAuthSignup(signup *api.SignUp) (*api.User, error) {
|
||||
return nil, errors.Wrap(err, "fail to read response body")
|
||||
}
|
||||
|
||||
type AuthSignupResponse struct {
|
||||
Data *api.User `json:"data"`
|
||||
}
|
||||
res := new(AuthSignupResponse)
|
||||
if err = json.Unmarshal(buf.Bytes(), res); err != nil {
|
||||
user := &api.User{}
|
||||
if err = json.Unmarshal(buf.Bytes(), user); err != nil {
|
||||
return nil, errors.Wrap(err, "fail to unmarshal post signup response")
|
||||
}
|
||||
return res.Data, nil
|
||||
return user, nil
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/usememos/memos/api"
|
||||
apiv1 "github.com/usememos/memos/api/v1"
|
||||
)
|
||||
|
||||
func TestMemoRelationServer(t *testing.T) {
|
||||
@ -18,7 +19,7 @@ func TestMemoRelationServer(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown(ctx)
|
||||
|
||||
signup := &api.SignUp{
|
||||
signup := &apiv1.SignUp{
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/usememos/memos/api"
|
||||
apiv1 "github.com/usememos/memos/api/v1"
|
||||
)
|
||||
|
||||
func TestMemoServer(t *testing.T) {
|
||||
@ -18,7 +19,7 @@ func TestMemoServer(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown(ctx)
|
||||
|
||||
signup := &api.SignUp{
|
||||
signup := &apiv1.SignUp{
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/usememos/memos/server"
|
||||
"github.com/usememos/memos/server/profile"
|
||||
"github.com/usememos/memos/store"
|
||||
"github.com/usememos/memos/store/db"
|
||||
"github.com/usememos/memos/test"
|
||||
|
||||
@ -34,19 +35,19 @@ func NewTestingServer(ctx context.Context, t *testing.T) (*TestingServer, error)
|
||||
return nil, errors.Wrap(err, "failed to open db")
|
||||
}
|
||||
|
||||
server, err := server.NewServer(ctx, profile)
|
||||
store := store.New(db.DBInstance, profile)
|
||||
server, err := server.NewServer(ctx, profile, store)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create server")
|
||||
}
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
s := &TestingServer{
|
||||
server: server,
|
||||
client: &http.Client{},
|
||||
profile: profile,
|
||||
cookie: "",
|
||||
}
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
if err := s.server.Start(ctx); err != nil {
|
||||
@ -126,7 +127,7 @@ func (s *TestingServer) request(method, uri string, body io.Reader, params, head
|
||||
}
|
||||
|
||||
if method == "POST" {
|
||||
if strings.Contains(uri, "/api/auth/login") || strings.Contains(uri, "/api/auth/signup") {
|
||||
if strings.Contains(uri, "/api/v1/auth/login") || strings.Contains(uri, "/api/v1/auth/signup") {
|
||||
cookie := ""
|
||||
h := resp.Header.Get("Set-Cookie")
|
||||
parts := strings.Split(h, "; ")
|
||||
@ -140,7 +141,7 @@ func (s *TestingServer) request(method, uri string, body io.Reader, params, head
|
||||
return nil, errors.Errorf("unable to find access token in the login response headers")
|
||||
}
|
||||
s.cookie = cookie
|
||||
} else if strings.Contains(uri, "/api/auth/logout") {
|
||||
} else if strings.Contains(uri, "/api/v1/auth/logout") {
|
||||
s.cookie = ""
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/usememos/memos/api"
|
||||
apiv1 "github.com/usememos/memos/api/v1"
|
||||
)
|
||||
|
||||
func TestSystemServer(t *testing.T) {
|
||||
@ -21,7 +22,7 @@ func TestSystemServer(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, (*api.User)(nil), status.Host)
|
||||
|
||||
signup := &api.SignUp{
|
||||
signup := &apiv1.SignUp{
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ export function vacuumDatabase() {
|
||||
}
|
||||
|
||||
export function signin(username: string, password: string) {
|
||||
return axios.post<ResponseObject<User>>("/api/auth/signin", {
|
||||
return axios.post("/api/v1/auth/signin", {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
export function signinWithSSO(identityProviderId: IdentityProviderId, code: string, redirectUri: string) {
|
||||
return axios.post<ResponseObject<User>>("/api/auth/signin/sso", {
|
||||
return axios.post("/api/v1/auth/signin/sso", {
|
||||
identityProviderId,
|
||||
code,
|
||||
redirectUri,
|
||||
@ -38,14 +38,14 @@ export function signinWithSSO(identityProviderId: IdentityProviderId, code: stri
|
||||
}
|
||||
|
||||
export function signup(username: string, password: string) {
|
||||
return axios.post<ResponseObject<User>>("/api/auth/signup", {
|
||||
return axios.post("/api/v1/auth/signup", {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
export function signout() {
|
||||
return axios.post("/api/auth/signout");
|
||||
return axios.post("/api/v1/auth/signout");
|
||||
}
|
||||
|
||||
export function createUser(userCreate: UserCreate) {
|
||||
|
Loading…
Reference in New Issue
Block a user