Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate standalone SQL store level #4

Merged
merged 8 commits into from
Jul 13, 2024
11 changes: 5 additions & 6 deletions server/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ var (
// REST APIs

type API struct {
app *app.App
authService string
permissions permissions.PermissionsService
MattermostAuth bool
logger mlog.LoggerIFace
audit *audit.Audit
app *app.App
authService string
permissions permissions.PermissionsService
logger mlog.LoggerIFace
audit *audit.Audit
}

func NewAPI(
Expand Down
48 changes: 2 additions & 46 deletions server/api/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,51 +204,7 @@ func (a *API) handleArchiveExportTeam(w http.ResponseWriter, r *http.Request) {
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
if a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in plugin mode"))
return
}

vars := mux.Vars(r)
teamID := vars["teamID"]

ctx := r.Context()
session, _ := ctx.Value(sessionContextKey).(*model.Session)
userID := session.UserID

auditRec := a.makeAuditRecord(r, "archiveExportTeam", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
auditRec.AddMeta("TeamID", teamID)

isGuest, err := a.userIsGuest(userID)
if err != nil {
a.errorResponse(w, r, err)
return
}

boards, err := a.app.GetBoardsForUserAndTeam(userID, teamID, !isGuest)
if err != nil {
a.errorResponse(w, r, err)
return
}
ids := []string{}
for _, board := range boards {
ids = append(ids, board.ID)
}

opts := model.ExportArchiveOptions{
TeamID: teamID,
BoardIDs: ids,
}

filename := fmt.Sprintf("archive-%s%s", time.Now().Format("2006-01-02"), archiveExtension)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment; filename="+filename)
w.Header().Set("Content-Transfer-Encoding", "binary")
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in plugin mode"))
Rajat-Dabade marked this conversation as resolved.
Show resolved Hide resolved
return

if err := a.app.ExportArchive(w, opts); err != nil {
a.errorResponse(w, r, err)
}

auditRec.Success()
}
37 changes: 4 additions & 33 deletions server/api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,16 @@ import (
"net/http"

"github.com/mattermost/mattermost-plugin-boards/server/model"
"github.com/mattermost/mattermost-plugin-boards/server/services/auth"
"github.com/mattermost/mattermost-plugin-boards/server/utils"

"github.com/mattermost/mattermost/server/public/shared/mlog"
)

func (a *API) sessionRequired(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return a.attachSession(handler, true)
return a.attachSession(handler)
}

func (a *API) attachSession(handler func(w http.ResponseWriter, r *http.Request), required bool) func(w http.ResponseWriter, r *http.Request) {
func (a *API) attachSession(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
token, _ := auth.ParseAuthTokenFromRequest(r)

if a.MattermostAuth && r.Header.Get("Mattermost-User-Id") != "" {
if r.Header.Get("Mattermost-User-Id") != "" {
userID := r.Header.Get("Mattermost-User-Id")
now := utils.GetMillis()
session := &model.Session{
Expand All @@ -37,30 +32,6 @@ func (a *API) attachSession(handler func(w http.ResponseWriter, r *http.Request)
return
}

session, err := a.app.GetSession(token)
if err != nil {
if required {
a.errorResponse(w, r, model.NewErrUnauthorized(err.Error()))
return
}

handler(w, r)
return
}

authService := session.AuthService
if authService != a.authService {
msg := `Session authService mismatch`
a.logger.Error(msg,
mlog.String("sessionID", session.ID),
mlog.String("want", a.authService),
mlog.String("got", authService),
)
a.errorResponse(w, r, model.NewErrUnauthorized(msg))
return
}

ctx := context.WithValue(r.Context(), sessionContextKey, session)
handler(w, r.WithContext(ctx))
a.errorResponse(w, r, model.NewErrUnauthorized("Unauthorized"))
}
}
2 changes: 1 addition & 1 deletion server/api/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

func (a *API) registerBlocksRoutes(r *mux.Router) {
// Blocks APIs
r.HandleFunc("/boards/{boardID}/blocks", a.attachSession(a.handleGetBlocks, false)).Methods("GET")
r.HandleFunc("/boards/{boardID}/blocks", a.attachSession(a.handleGetBlocks)).Methods("GET")
r.HandleFunc("/boards/{boardID}/blocks", a.sessionRequired(a.handlePostBlocks)).Methods("POST")
r.HandleFunc("/boards/{boardID}/blocks", a.sessionRequired(a.handlePatchBlocks)).Methods("PATCH")
r.HandleFunc("/boards/{boardID}/blocks/{blockID}", a.sessionRequired(a.handleDeleteBlock)).Methods("DELETE")
Expand Down
2 changes: 1 addition & 1 deletion server/api/boards.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func (a *API) registerBoardsRoutes(r *mux.Router) {
r.HandleFunc("/teams/{teamID}/boards", a.sessionRequired(a.handleGetBoards)).Methods("GET")
r.HandleFunc("/boards", a.sessionRequired(a.handleCreateBoard)).Methods("POST")
r.HandleFunc("/boards/{boardID}", a.attachSession(a.handleGetBoard, false)).Methods("GET")
r.HandleFunc("/boards/{boardID}", a.attachSession(a.handleGetBoard)).Methods("GET")
r.HandleFunc("/boards/{boardID}", a.sessionRequired(a.handlePatchBoard)).Methods("PATCH")
r.HandleFunc("/boards/{boardID}", a.sessionRequired(a.handleDeleteBoard)).Methods("DELETE")
r.HandleFunc("/boards/{boardID}/duplicate", a.sessionRequired(a.handleDuplicateBoard)).Methods("POST")
Expand Down
5 changes: 0 additions & 5 deletions server/api/channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ func (a *API) handleGetChannel(w http.ResponseWriter, r *http.Request) {
// schema:
// "$ref": "#/definitions/ErrorResponse"

if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}

teamID := mux.Vars(r)["teamID"]
channelID := mux.Vars(r)["channelID"]
userID := getUserID(r)
Expand Down
4 changes: 2 additions & 2 deletions server/api/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func FileInfoResponseFromJSON(data io.Reader) (*mmModel.FileInfo, error) {

func (a *API) registerFilesRoutes(r *mux.Router) {
// Files API
r.HandleFunc("/files/teams/{teamID}/{boardID}/{filename}", a.attachSession(a.handleServeFile, false)).Methods("GET")
r.HandleFunc("/files/teams/{teamID}/{boardID}/{filename}/info", a.attachSession(a.getFileInfo, false)).Methods("GET")
r.HandleFunc("/files/teams/{teamID}/{boardID}/{filename}", a.attachSession(a.handleServeFile)).Methods("GET")
r.HandleFunc("/files/teams/{teamID}/{boardID}/{filename}/info", a.attachSession(a.getFileInfo)).Methods("GET")
r.HandleFunc("/teams/{teamID}/{boardID}/files", a.sessionRequired(a.handleUploadFile)).Methods("POST")
}

Expand Down
10 changes: 0 additions & 10 deletions server/api/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ func (a *API) handleSearchMyChannels(w http.ResponseWriter, r *http.Request) {
// schema:
// "$ref": "#/definitions/ErrorResponse"

if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}

query := r.URL.Query()
searchQuery := query.Get("search")

Expand Down Expand Up @@ -226,11 +221,6 @@ func (a *API) handleSearchLinkableBoards(w http.ResponseWriter, r *http.Request)
// schema:
// "$ref": "#/definitions/ErrorResponse"

if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}

teamID := mux.Vars(r)["teamID"]
term := r.URL.Query().Get("q")
userID := getUserID(r)
Expand Down
4 changes: 0 additions & 4 deletions server/api/statistics.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ func (a *API) handleStatistics(w http.ResponseWriter, r *http.Request) {
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
if !a.MattermostAuth {
a.errorResponse(w, r, model.NewErrNotImplemented("not permitted in standalone mode"))
return
}

// user must have right to access analytics
userID := getUserID(r)
Expand Down
20 changes: 6 additions & 14 deletions server/api/teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,12 @@ func (a *API) handleGetTeam(w http.ResponseWriter, r *http.Request) {
var team *model.Team
var err error

if a.MattermostAuth {
team, err = a.app.GetTeam(teamID)
if model.IsErrNotFound(err) {
a.errorResponse(w, r, model.NewErrUnauthorized("invalid team"))
}
if err != nil {
a.errorResponse(w, r, err)
}
} else {
team, err = a.app.GetRootTeam()
if err != nil {
a.errorResponse(w, r, err)
return
}
team, err = a.app.GetTeam(teamID)
if model.IsErrNotFound(err) {
a.errorResponse(w, r, model.NewErrUnauthorized("invalid team"))
}
if err != nil {
a.errorResponse(w, r, err)
}

auditRec := a.makeAuditRecord(r, "getTeam", audit.Fail)
Expand Down
5 changes: 0 additions & 5 deletions server/app/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ const (
SecondsPerMinute = 60
)

// GetSession Get a user active session and refresh the session if is needed.
func (a *App) GetSession(token string) (*model.Session, error) {
return a.auth.GetSession(token)
}

// IsValidReadToken validates the read token for a block.
func (a *App) IsValidReadToken(boardID string, readToken string) (bool, error) {
return a.auth.IsValidReadToken(boardID, readToken)
Expand Down
3 changes: 1 addition & 2 deletions server/app/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ func SetupTestHelper(t *testing.T) (*TestHelper, func()) {
filesBackend := &mocks.FileBackend{}
auth := auth.New(&cfg, store, nil)
logger, _ := mlog.NewLogger()
sessionToken := "TESTTOKEN"
wsserver := ws.NewServer(auth, sessionToken, false, logger, store)
wsserver := ws.NewServer(auth, logger, store)
webhook := webhook.NewClient(&cfg, logger)
metricsService := metrics.NewMetrics(metrics.InstanceInfo{})

Expand Down
18 changes: 0 additions & 18 deletions server/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ import (
"github.com/mattermost/mattermost-plugin-boards/server/services/config"
"github.com/mattermost/mattermost-plugin-boards/server/services/permissions"
"github.com/mattermost/mattermost-plugin-boards/server/services/store"
"github.com/mattermost/mattermost-plugin-boards/server/utils"
"github.com/pkg/errors"
)

type AuthInterface interface {
GetSession(token string) (*model.Session, error)
IsValidReadToken(boardID string, readToken string) (bool, error)
DoesUserHaveTeamAccess(userID string, teamID string) bool
}
Expand All @@ -28,22 +26,6 @@ func New(config *config.Configuration, store store.Store, permissions permission
return &Auth{config: config, store: store, permissions: permissions}
}

// GetSession Get a user active session and refresh the session if needed.
func (a *Auth) GetSession(token string) (*model.Session, error) {
if len(token) < 1 {
return nil, errors.New("no session token")
}

session, err := a.store.GetSession(token, a.config.SessionExpireTime)
if err != nil {
return nil, errors.Wrap(err, "unable to get the session for the token")
}
if session.UpdateAt < (utils.GetMillis() - utils.SecondsToMillis(a.config.SessionRefreshTime)) {
_ = a.store.RefreshSession(session)
}
return session, nil
}

// IsValidReadToken validates the read token for a board.
func (a *Auth) IsValidReadToken(boardID string, readToken string) (bool, error) {
sharing, err := a.store.GetSharing(boardID)
Expand Down
74 changes: 0 additions & 74 deletions server/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,8 @@ package auth
import (
"testing"

"github.com/golang/mock/gomock"
"github.com/mattermost/mattermost-plugin-boards/server/model"
"github.com/mattermost/mattermost-plugin-boards/server/services/config"
"github.com/mattermost/mattermost-plugin-boards/server/services/permissions/localpermissions"
mockpermissions "github.com/mattermost/mattermost-plugin-boards/server/services/permissions/mocks"
"github.com/mattermost/mattermost-plugin-boards/server/services/store/mockstore"
"github.com/mattermost/mattermost-plugin-boards/server/utils"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

"github.com/mattermost/mattermost/server/public/shared/mlog"
)

type TestHelper struct {
Expand All @@ -22,71 +13,6 @@ type TestHelper struct {
Store *mockstore.MockStore
}

var mockSession = &model.Session{
ID: utils.NewID(utils.IDTypeSession),
Token: "goodToken",
UserID: "12345",
CreateAt: utils.GetMillis() - utils.SecondsToMillis(2000),
UpdateAt: utils.GetMillis() - utils.SecondsToMillis(2000),
}

func setupTestHelper(t *testing.T) *TestHelper {
ctrl := gomock.NewController(t)
ctrlPermissions := gomock.NewController(t)
cfg := config.Configuration{}
mockStore := mockstore.NewMockStore(ctrl)
mockPermissions := mockpermissions.NewMockStore(ctrlPermissions)
logger, err := mlog.NewLogger()
require.NoError(t, err)
newAuth := New(&cfg, mockStore, localpermissions.New(mockPermissions, logger))

// called during default template setup for every test
mockStore.EXPECT().GetTemplateBoards("0", "").AnyTimes()
mockStore.EXPECT().RemoveDefaultTemplates(gomock.Any()).AnyTimes()
mockStore.EXPECT().InsertBlock(gomock.Any(), gomock.Any()).AnyTimes()

return &TestHelper{
Auth: newAuth,
Session: *mockSession,
Store: mockStore,
}
}

func TestGetSession(t *testing.T) {
th := setupTestHelper(t)

testcases := []struct {
title string
token string
refreshTime int64
isError bool
}{
{"fail, no token", "", 0, true},
{"fail, invalid username", "badToken", 0, true},
{"success, good token", "goodToken", 1000, false},
}

th.Store.EXPECT().GetSession("badToken", gomock.Any()).Return(nil, errors.New("Invalid Token"))
th.Store.EXPECT().GetSession("goodToken", gomock.Any()).Return(mockSession, nil)
th.Store.EXPECT().RefreshSession(gomock.Any()).Return(nil)

for _, test := range testcases {
t.Run(test.title, func(t *testing.T) {
if test.refreshTime > 0 {
th.Auth.config.SessionRefreshTime = test.refreshTime
}

session, err := th.Auth.GetSession(test.token)
if test.isError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.NotNil(t, session)
}
})
}
}

Rajat-Dabade marked this conversation as resolved.
Show resolved Hide resolved
func TestIsValidReadToken(t *testing.T) {
// ToDo: reimplement

Expand Down
10 changes: 4 additions & 6 deletions server/boards/boardsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,11 @@ func NewBoardsApp(api model.ServicesAPI) (*BoardsApp, error) {
if err != nil {
return nil, fmt.Errorf("error initializing the DB: %w", err)
}
if cfg.AuthMode == server.MattermostAuthMod {
layeredStore, err2 := mattermostauthlayer.New(cfg.DBType, sqlDB, db, logger, api, storeParams.TablePrefix)
if err2 != nil {
return nil, fmt.Errorf("error initializing the DB: %w", err2)
}
db = layeredStore
layeredStore, err2 := mattermostauthlayer.New(cfg.DBType, sqlDB, db, logger, api, storeParams.TablePrefix)
if err2 != nil {
return nil, fmt.Errorf("error initializing the DB: %w", err2)
}
db = layeredStore

permissionsService := mmpermissions.New(db, api, logger)

Expand Down
Loading