More flexible "system", move to Corteza
- more control over starting procedure, cli commands... - fix package paths - remove separated system-cli entrypoint - renaming symbols, comments, strings from Crust to Corteza
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
)
|
||||
|
||||
func StartCLI(ctx context.Context) {
|
||||
var (
|
||||
db = repository.DB(ctx)
|
||||
settingsService = settings.NewService(settings.NewRepository(db, "sys_settings"))
|
||||
|
||||
cmd = &cobra.Command{Use: "system-cli"}
|
||||
)
|
||||
|
||||
cmd.AddCommand(
|
||||
settingsCmd(ctx, settingsService),
|
||||
authCmd(ctx, db, settingsService),
|
||||
usersCmd(ctx, db),
|
||||
rolesCmd(ctx, db),
|
||||
)
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func exit(cmd *cobra.Command, err error) {
|
||||
if err != nil {
|
||||
cmd.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
func rolesCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "roles",
|
||||
Short: "Role management",
|
||||
}
|
||||
|
||||
addUserCmd := &cobra.Command{
|
||||
Use: "useradd [role-ID-or-name-or-handle] [user-ID-or-email]",
|
||||
Short: "Add user to role",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: rolesUserAddCmd(ctx, db),
|
||||
}
|
||||
|
||||
cmd.AddCommand(addUserCmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func rolesUserAddCmd(ctx context.Context, db *factory.DB) func(cmd *cobra.Command, args []string) {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
// Create role and user repository.
|
||||
var (
|
||||
roleStr, userStr = args[0], args[1]
|
||||
|
||||
roleRepo = repository.Role(ctx, db)
|
||||
userRepo = repository.User(ctx, db)
|
||||
|
||||
rr []*types.Role
|
||||
role *types.Role
|
||||
user *types.User
|
||||
ID uint64
|
||||
|
||||
err error
|
||||
)
|
||||
|
||||
// Try to find role by name and by ID
|
||||
if rr, err = roleRepo.Find(&types.RoleFilter{Query: roleStr}); err != nil {
|
||||
exit(cmd, err)
|
||||
} else if len(rr) == 1 {
|
||||
role = rr[0]
|
||||
} else if len(rr) > 1 {
|
||||
exit(cmd, errors.Errorf("too many roles found with name %q", roleStr))
|
||||
} else if role == nil {
|
||||
if ID, err = strconv.ParseUint(roleStr, 10, 64); err != nil {
|
||||
// Could not parse ID out of role string
|
||||
return
|
||||
} else if role, err = roleRepo.FindByID(ID); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if user, err = userRepo.FindByEmail(userStr); repository.ErrUserNotFound.Eq(err) {
|
||||
exit(cmd, err)
|
||||
} else if user == nil || user.ID == 0 {
|
||||
if ID, err = strconv.ParseUint(userStr, 10, 64); err != nil {
|
||||
exit(cmd, err)
|
||||
} else if user, err = userRepo.FindByID(ID); err != nil {
|
||||
exit(cmd, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add user to role.
|
||||
if err = roleRepo.MemberAddByID(role.ID, user.ID); err != nil {
|
||||
exit(cmd, err)
|
||||
}
|
||||
|
||||
cmd.Printf("Added user [%d] %q to [%d] %q role\n", user.ID, user.Email, role.ID, role.Name)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cli
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -8,16 +8,15 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
"github.com/crusttech/crust/system/internal/auth/external"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/auth/external"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
// Will perform OpenID connect auto-configuration
|
||||
func authCmd(ctx context.Context, db *factory.DB, settingsService settings.Service) *cobra.Command {
|
||||
func Auth(ctx context.Context) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "auth",
|
||||
Short: "External authentication",
|
||||
@@ -30,14 +29,14 @@ func authCmd(ctx context.Context, db *factory.DB, settingsService settings.Servi
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var name, url = args[0], args[1]
|
||||
|
||||
if eas, err := external.ExternalAuthSettings(settingsService); err != nil {
|
||||
exit(cmd, err)
|
||||
if eas, err := external.ExternalAuthSettings(service.DefaultIntSettings); err != nil {
|
||||
exit(err)
|
||||
} else if eap, err := external.RegisterNewOpenIdClient(ctx, eas, name, url); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
} else if vv, err := eap.MakeValueSet("openid-connect." + name); err != nil {
|
||||
exit(cmd, err)
|
||||
} else if err := settingsService.BulkSet(vv); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
} else if err := service.DefaultIntSettings.BulkSet(vv); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -48,6 +47,8 @@ func authCmd(ctx context.Context, db *factory.DB, settingsService settings.Servi
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var (
|
||||
db = factory.Database.MustGet("system")
|
||||
|
||||
userRepo = repository.User(ctx, db)
|
||||
roleRepo = repository.Role(ctx, db)
|
||||
// authSvc = service.Auth(ctx)
|
||||
@@ -73,7 +74,7 @@ func authCmd(ctx context.Context, db *factory.DB, settingsService settings.Servi
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
user.SetRoles(rr.IDs())
|
||||
@@ -94,12 +95,12 @@ func authCmd(ctx context.Context, db *factory.DB, settingsService settings.Servi
|
||||
|
||||
err = ntf.EmailConfirmation("en", args[0], "notification-testing-token")
|
||||
if err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
err = ntf.PasswordReset("en", args[0], "notification-testing-token")
|
||||
if err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
},
|
||||
@@ -0,0 +1,11 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func exit(err error) {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func Roles(ctx context.Context) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "roles",
|
||||
Short: "Role management",
|
||||
}
|
||||
|
||||
addUserCmd := &cobra.Command{
|
||||
Use: "useradd [role-ID-or-name-or-handle] [user-ID-or-email]",
|
||||
Short: "Add user to role",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Create role and user repository.
|
||||
var (
|
||||
db = factory.Database.MustGet("system")
|
||||
|
||||
roleStr, userStr = args[0], args[1]
|
||||
|
||||
roleRepo = repository.Role(ctx, db)
|
||||
userRepo = repository.User(ctx, db)
|
||||
|
||||
rr []*types.Role
|
||||
role *types.Role
|
||||
user *types.User
|
||||
ID uint64
|
||||
|
||||
err error
|
||||
)
|
||||
|
||||
// Try to find role by name and by ID
|
||||
if rr, err = roleRepo.Find(&types.RoleFilter{Query: roleStr}); err != nil {
|
||||
exit(err)
|
||||
} else if len(rr) == 1 {
|
||||
role = rr[0]
|
||||
} else if len(rr) > 1 {
|
||||
exit(errors.Errorf("too many roles found with name %q", roleStr))
|
||||
} else if role == nil {
|
||||
if ID, err = strconv.ParseUint(roleStr, 10, 64); err != nil {
|
||||
// Could not parse ID out of role string
|
||||
return
|
||||
} else if role, err = roleRepo.FindByID(ID); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if user, err = userRepo.FindByEmail(userStr); repository.ErrUserNotFound.Eq(err) {
|
||||
exit(err)
|
||||
} else if user == nil || user.ID == 0 {
|
||||
if ID, err = strconv.ParseUint(userStr, 10, 64); err != nil {
|
||||
exit(err)
|
||||
} else if user, err = userRepo.FindByID(ID); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add user to role.
|
||||
if err = roleRepo.MemberAddByID(role.ID, user.ID); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
||||
cmd.Printf("Added user [%d] %q to [%d] %q role\n", user.ID, user.Email, role.ID, role.Name)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(addUserCmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cli
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -8,46 +8,72 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/crusttech/crust/internal/rand"
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
systemService "github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/internal/rand"
|
||||
"github.com/cortezaproject/corteza-server/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
)
|
||||
|
||||
func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "settings",
|
||||
Short: "Settings management",
|
||||
}
|
||||
func Settings(ctx context.Context) *cobra.Command {
|
||||
var (
|
||||
systemApiUrl, authFrontendUrl, authFromAddress, authFromName string
|
||||
|
||||
cmd = &cobra.Command{
|
||||
Use: "settings",
|
||||
Short: "Settings management",
|
||||
}
|
||||
)
|
||||
|
||||
auto := &cobra.Command{
|
||||
Use: "auto-configure",
|
||||
Short: "Run autoconfiguration",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
systemService.DefaultSettings.LoadAuthSettings()
|
||||
_, _ = service.DefaultSettings.LoadAuthSettings()
|
||||
|
||||
settingsAutoConfigure(
|
||||
cmd,
|
||||
setSvc,
|
||||
cmd.Flags().Lookup("system-api-url").Value.String(),
|
||||
cmd.Flags().Lookup("auth-frontend-url").Value.String(),
|
||||
cmd.Flags().Lookup("auth-from-address").Value.String(),
|
||||
cmd.Flags().Lookup("auth-from-address").Value.String(),
|
||||
systemApiUrl,
|
||||
authFrontendUrl,
|
||||
authFromAddress,
|
||||
authFromName,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
auto.Flags().String("system-api-url", "", "System API URL (http://sytem.api.example.tld)")
|
||||
auto.Flags().String("auth-frontend-url", "", "http://example.tld")
|
||||
auto.Flags().String("auth-from-address", "", "name@example.tld")
|
||||
auto.Flags().String("auth-from-name", "", "Name Surname")
|
||||
auto.Flags().StringVar(
|
||||
&systemApiUrl,
|
||||
"system-api-url",
|
||||
"",
|
||||
"System API URL (http://sytem.api.example.tld)",
|
||||
)
|
||||
|
||||
auto.Flags().StringVar(
|
||||
&authFrontendUrl,
|
||||
"auth-frontend-url",
|
||||
"",
|
||||
"http://example.tld",
|
||||
)
|
||||
|
||||
auto.Flags().StringVar(
|
||||
&authFromAddress,
|
||||
"auth-from-address",
|
||||
"",
|
||||
"name@example.tld",
|
||||
)
|
||||
|
||||
auto.Flags().StringVar(
|
||||
&authFromName,
|
||||
"auth-from-name",
|
||||
"",
|
||||
"Name Surname",
|
||||
)
|
||||
|
||||
list := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
prefix := cmd.Flags().Lookup("prefix").Value.String()
|
||||
if kv, err := setSvc.FindByPrefix(prefix); err != nil {
|
||||
exit(cmd, err)
|
||||
if kv, err := service.DefaultIntSettings.FindByPrefix(prefix); err != nil {
|
||||
exit(err)
|
||||
} else {
|
||||
for _, v := range kv {
|
||||
cmd.Printf("%s\t%v\n", v.Name, v.Value)
|
||||
@@ -64,12 +90,12 @@ func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command {
|
||||
Short: "Get value (raw JSON) for a specific key",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if v, err := setSvc.Get(args[0], 0); err != nil {
|
||||
exit(cmd, err)
|
||||
if v, err := service.DefaultIntSettings.Get(args[0], 0); err != nil {
|
||||
exit(err)
|
||||
} else if v != nil {
|
||||
cmd.Printf("%v\n", v.Value)
|
||||
}
|
||||
exit(cmd, nil)
|
||||
exit(nil)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -84,10 +110,10 @@ func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command {
|
||||
}
|
||||
|
||||
if err := v.SetValueAsString(value); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
exit(cmd, setSvc.Set(v))
|
||||
exit(service.DefaultIntSettings.Set(v))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -96,7 +122,7 @@ func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command {
|
||||
Short: "Set value (raw JSON) for a specific key",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
exit(cmd, setSvc.Delete(args[0], 0))
|
||||
exit(service.DefaultIntSettings.Delete(args[0], 0))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -111,7 +137,7 @@ func settingsCmd(ctx context.Context, setSvc settings.Service) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func settingsAutoConfigure(cmd *cobra.Command, setSvc settings.Service, systemApiUrl, frontendUrl, fromAddress, fromName string) {
|
||||
func settingsAutoConfigure(cmd *cobra.Command, systemApiUrl, frontendUrl, fromAddress, fromName string) {
|
||||
set := func(name string, value interface{}) {
|
||||
var (
|
||||
v *settings.Value
|
||||
@@ -137,14 +163,14 @@ func settingsAutoConfigure(cmd *cobra.Command, setSvc settings.Service, systemAp
|
||||
}
|
||||
}
|
||||
|
||||
err = setSvc.Set(v)
|
||||
err = service.DefaultIntSettings.Set(v)
|
||||
if err != nil {
|
||||
cmd.Printf("could not store setting: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
setIfMissing := func(name string, value interface{}) {
|
||||
if existing, err := setSvc.Get(name, 0); err == nil && existing == nil {
|
||||
if existing, err := service.DefaultIntSettings.Get(name, 0); err == nil && existing == nil {
|
||||
set(name, value)
|
||||
}
|
||||
}
|
||||
@@ -178,8 +204,8 @@ func settingsAutoConfigure(cmd *cobra.Command, setSvc settings.Service, systemAp
|
||||
|
||||
setIfMissing("auth.external.session-store-secure", func() interface{} {
|
||||
// Try to determines if we need secure session store from redirect URL scheme
|
||||
extRedirUrl, _ := setSvc.GetGlobalString("auth.external.redirect-url")
|
||||
return strings.Index(extRedirUrl, "https://") > -1
|
||||
extRedirUrl, _ := service.DefaultIntSettings.GetGlobalString("auth.external.redirect-url")
|
||||
return strings.Contains(extRedirUrl, "https://")
|
||||
})
|
||||
|
||||
if len(frontendUrl) > 0 {
|
||||
@@ -205,7 +231,7 @@ func settingsAutoConfigure(cmd *cobra.Command, setSvc settings.Service, systemAp
|
||||
if len(fromAddress) > 0 {
|
||||
return fromAddress
|
||||
}
|
||||
return "change-me@local.crust.tech"
|
||||
return "change-me@example.tld"
|
||||
})
|
||||
|
||||
setIfMissing("auth.mail.from-name", func() interface{} {
|
||||
@@ -213,7 +239,7 @@ func settingsAutoConfigure(cmd *cobra.Command, setSvc settings.Service, systemAp
|
||||
return fromName
|
||||
}
|
||||
|
||||
return "Crust Team"
|
||||
return "Corteza Team"
|
||||
})
|
||||
|
||||
// No external providers preconfigured, so disable
|
||||
@@ -1,4 +1,4 @@
|
||||
package cli
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"github.com/titpetric/factory"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
func Users(ctx context.Context) *cobra.Command {
|
||||
// User management commands.
|
||||
cmd := &cobra.Command{
|
||||
Use: "users",
|
||||
@@ -26,6 +26,10 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
Use: "list",
|
||||
Short: "List users",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var (
|
||||
db = factory.Database.MustGet("system")
|
||||
)
|
||||
|
||||
userRepo := repository.User(ctx, db)
|
||||
uf := &types.UserFilter{
|
||||
OrderBy: "updated_at",
|
||||
@@ -33,7 +37,7 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
|
||||
users, err := userRepo.Find(uf)
|
||||
if err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
fmt.Println(" Created Updated EmailAddress")
|
||||
@@ -61,6 +65,8 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var (
|
||||
db = factory.Database.MustGet("system")
|
||||
|
||||
userRepo = repository.User(ctx, db)
|
||||
authSvc = service.Auth(ctx)
|
||||
|
||||
@@ -72,23 +78,23 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
)
|
||||
|
||||
if user, err = userRepo.Create(user); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
cmd.Printf("User created [%d].\n", user.ID)
|
||||
|
||||
cmd.Print("Set password: ")
|
||||
if password, err = terminal.ReadPassword(syscall.Stdin); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
if len(password) == 0 {
|
||||
// Password not set, that's ok too.
|
||||
exit(cmd, nil)
|
||||
exit(nil)
|
||||
}
|
||||
|
||||
if err = authSvc.SetPassword(user.ID, string(password)); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -99,6 +105,8 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var (
|
||||
db = factory.Database.MustGet("system")
|
||||
|
||||
userRepo = repository.User(ctx, db)
|
||||
authSvc = service.Auth(ctx)
|
||||
|
||||
@@ -108,21 +116,21 @@ func usersCmd(ctx context.Context, db *factory.DB) *cobra.Command {
|
||||
)
|
||||
|
||||
if user, err = userRepo.FindByEmail(args[0]); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
cmd.Print("Set password: ")
|
||||
if password, err = terminal.ReadPassword(syscall.Stdin); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
|
||||
if len(password) == 0 {
|
||||
// Password not set, that's ok too.
|
||||
exit(cmd, nil)
|
||||
exit(nil)
|
||||
}
|
||||
|
||||
if err = authSvc.SetPassword(user.ID, string(password)); err != nil {
|
||||
exit(cmd, err)
|
||||
exit(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/db/mysql"
|
||||
"github.com/cortezaproject/corteza-server/system/db/mysql"
|
||||
)
|
||||
|
||||
func statements(contents []byte, err error) ([]string, error) {
|
||||
@@ -31,13 +31,17 @@ func Migrate(db *factory.DB) error {
|
||||
|
||||
var files []string
|
||||
|
||||
if err := fs.Walk(statikFS, "/", func(filename string, info os.FileInfo, err error) error {
|
||||
fn := func(filename string, info os.FileInfo, err error) error {
|
||||
_ = err
|
||||
matched, err := filepath.Match("/*.up.sql", filename)
|
||||
if matched {
|
||||
files = append(files, filename)
|
||||
}
|
||||
|
||||
return err
|
||||
}); err != nil {
|
||||
}
|
||||
|
||||
if err := fs.Walk(statikFS, "/", fn); err != nil {
|
||||
return errors.Wrap(err, "Error when listing files for migrations")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,27 +3,17 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/namsral/flag"
|
||||
"github.com/titpetric/factory"
|
||||
)
|
||||
|
||||
func TestMigrations(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
return
|
||||
}
|
||||
factory.Database.Add("system", os.Getenv("SYSTEM_DB_DSN"))
|
||||
db := factory.Database.MustGet("system")
|
||||
db.Profiler = &factory.Database.ProfilerStdout
|
||||
|
||||
var dsn string
|
||||
|
||||
flag.StringVar(&dsn, "db-dsn", "crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci", "DSN for database connection")
|
||||
flag.Parse()
|
||||
|
||||
factory.Database.Add("default", dsn)
|
||||
factory.Database.Add("system", dsn)
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
if err := Migrate(db); err != nil {
|
||||
t.Fatalf("Unexpected error: %#v", err)
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/config"
|
||||
)
|
||||
|
||||
type (
|
||||
appFlags struct {
|
||||
smtp *config.SMTP
|
||||
http *config.HTTP
|
||||
monitor *config.Monitor
|
||||
db *config.Database
|
||||
jwt *config.JWT
|
||||
}
|
||||
)
|
||||
|
||||
var flags *appFlags
|
||||
|
||||
func (c *appFlags) Validate() error {
|
||||
if c == nil {
|
||||
return errors.New("Flags are not initialized, need to call Flags()")
|
||||
}
|
||||
if err := c.http.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.smtp.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.monitor.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.db.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Flags(prefix ...string) {
|
||||
if flags != nil {
|
||||
return
|
||||
}
|
||||
if len(prefix) == 0 {
|
||||
panic("Flags() needs prefix on first call")
|
||||
}
|
||||
flags = &appFlags{
|
||||
new(config.SMTP).Init(prefix...),
|
||||
new(config.HTTP).Init(prefix...),
|
||||
new(config.Monitor).Init(prefix...),
|
||||
new(config.Database).Init(prefix...),
|
||||
new(config.JWT).Init(),
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -3,8 +3,8 @@ package external
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/internal/settings"
|
||||
)
|
||||
|
||||
func Init(settingsService settings.Service) {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
+3
-1
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/crusttech/go-oidc"
|
||||
)
|
||||
|
||||
// @todo remove dependency on github.com/crusttech/go-oidc (and github.com/coreos/go-oidc)
|
||||
// and move client registration to corteza codebase
|
||||
func RegisterNewOpenIdClient(ctx context.Context, eas *externalAuthSettings, name, url string) (eap *externalAuthProvider, err error) {
|
||||
var (
|
||||
provider *oidc.Provider
|
||||
@@ -19,7 +21,7 @@ func RegisterNewOpenIdClient(ctx context.Context, eas *externalAuthSettings, nam
|
||||
}
|
||||
|
||||
client, err = provider.RegisterClient(ctx, &oidc.ClientRegistration{
|
||||
Name: "Crust",
|
||||
Name: "Corteza",
|
||||
RedirectURIs: []string{redirectUrl},
|
||||
ResponseTypes: []string{"token id_token", "code"},
|
||||
})
|
||||
|
||||
+2
-4
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/rand"
|
||||
intset "github.com/crusttech/crust/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/internal/rand"
|
||||
intset "github.com/cortezaproject/corteza-server/internal/settings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,8 +28,6 @@ type (
|
||||
sessionStoreSecret string
|
||||
sessionStoreSecure bool
|
||||
providers map[string]externalAuthProvider
|
||||
|
||||
service intset.Service
|
||||
}
|
||||
|
||||
externalAuthProvider struct {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
intset "github.com/crusttech/crust/internal/settings"
|
||||
intset "github.com/cortezaproject/corteza-server/internal/settings"
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -26,8 +26,7 @@ type (
|
||||
*repository
|
||||
|
||||
// sql table reference
|
||||
applications string
|
||||
members string
|
||||
table string
|
||||
}
|
||||
)
|
||||
|
||||
@@ -44,13 +43,13 @@ func Application(ctx context.Context, db *factory.DB) ApplicationRepository {
|
||||
|
||||
func (r *application) With(ctx context.Context, db *factory.DB) ApplicationRepository {
|
||||
return &application{
|
||||
repository: r.repository.With(ctx, db),
|
||||
applications: "sys_application",
|
||||
repository: r.repository.With(ctx, db),
|
||||
table: "sys_application",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *application) FindByID(id uint64) (*types.Application, error) {
|
||||
sql := "SELECT " + sqlApplicationColumns + " FROM " + r.applications + " WHERE id = ? AND " + sqlApplicationScope
|
||||
sql := "SELECT " + sqlApplicationColumns + " FROM " + r.table + " WHERE id = ? AND " + sqlApplicationScope
|
||||
mod := &types.Application{}
|
||||
|
||||
return mod, isFound(r.db().Get(mod, sql, id), mod.ID > 0, ErrApplicationNotFound)
|
||||
@@ -60,7 +59,7 @@ func (r *application) Find() (types.ApplicationSet, error) {
|
||||
rval := make([]*types.Application, 0)
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
sql := "SELECT " + sqlApplicationColumns + " FROM " + r.applications + " WHERE " + sqlApplicationScope
|
||||
sql := "SELECT " + sqlApplicationColumns + " FROM " + r.table + " WHERE " + sqlApplicationScope
|
||||
|
||||
sql += " ORDER BY id ASC"
|
||||
|
||||
@@ -71,15 +70,15 @@ func (r *application) Create(mod *types.Application) (*types.Application, error)
|
||||
mod.ID = factory.Sonyflake.NextID()
|
||||
mod.CreatedAt = time.Now()
|
||||
|
||||
return mod, r.db().Insert(r.applications, mod)
|
||||
return mod, r.db().Insert(r.table, mod)
|
||||
}
|
||||
|
||||
func (r *application) Update(mod *types.Application) (*types.Application, error) {
|
||||
mod.UpdatedAt = timeNowPtr()
|
||||
|
||||
return mod, r.db().Replace(r.applications, mod)
|
||||
return mod, r.db().Replace(r.table, mod)
|
||||
}
|
||||
|
||||
func (r *application) DeleteByID(id uint64) error {
|
||||
return r.updateColumnByID(r.applications, "deleted_at", time.Now(), id)
|
||||
return r.updateColumnByID(r.table, "deleted_at", time.Now(), id)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func TestApplication(t *testing.T) {
|
||||
@@ -19,7 +19,7 @@ func TestApplication(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
db := factory.Database.MustGet("system")
|
||||
|
||||
// Create application repository.
|
||||
crepo := Application(context.Background(), db)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func TestCredentials(t *testing.T) {
|
||||
@@ -19,7 +19,7 @@ func TestCredentials(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
db := factory.Database.MustGet("system")
|
||||
|
||||
// Create credentials repository.
|
||||
crepo := Credentials(context.Background(), db)
|
||||
|
||||
@@ -14,7 +14,7 @@ func (e repositoryError) Error() string {
|
||||
}
|
||||
|
||||
func (e repositoryError) String() string {
|
||||
return "crust.system.repository." + string(e)
|
||||
return "system.repository." + string(e)
|
||||
}
|
||||
|
||||
func (e repositoryError) Eq(err error) bool {
|
||||
|
||||
@@ -7,21 +7,14 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/namsral/flag"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
systemMigrate "github.com/crusttech/crust/system/db"
|
||||
systemMigrate "github.com/cortezaproject/corteza-server/system/db"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dsn := ""
|
||||
flag.StringVar(&dsn, "db-dsn", "crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci", "DSN for database connection")
|
||||
flag.Parse()
|
||||
|
||||
factory.Database.Add("default", dsn)
|
||||
factory.Database.Add("system", dsn)
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
factory.Database.Add("system", os.Getenv("SYSTEM_DB_DSN"))
|
||||
db := factory.Database.MustGet("system")
|
||||
db.Profiler = &factory.Database.ProfilerStdout
|
||||
|
||||
// migrate database schema
|
||||
|
||||
@@ -6,11 +6,12 @@ package repository
|
||||
|
||||
import (
|
||||
context "context"
|
||||
repository "github.com/crusttech/crust/system/internal/repository"
|
||||
types "github.com/crusttech/crust/system/types"
|
||||
reflect "reflect"
|
||||
|
||||
repository "github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
types "github.com/cortezaproject/corteza-server/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
factory "github.com/titpetric/factory"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockCredentialsRepository is a mock of CredentialsRepository interface
|
||||
|
||||
@@ -6,12 +6,13 @@ package repository
|
||||
|
||||
import (
|
||||
context "context"
|
||||
repository "github.com/crusttech/crust/system/internal/repository"
|
||||
types "github.com/crusttech/crust/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
factory "github.com/titpetric/factory"
|
||||
io "io"
|
||||
reflect "reflect"
|
||||
|
||||
repository "github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
types "github.com/cortezaproject/corteza-server/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
factory "github.com/titpetric/factory"
|
||||
)
|
||||
|
||||
// MockUserRepository is a mock of UserRepository interface
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func TestOrganisation(t *testing.T) {
|
||||
@@ -19,7 +19,7 @@ func TestOrganisation(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
db := factory.Database.MustGet("system")
|
||||
|
||||
// Run tests in transaction to maintain DB state.
|
||||
test.Error(t, db.Transaction(func() error {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
func TestRepository(t *testing.T) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func TestRole(t *testing.T) {
|
||||
@@ -19,7 +19,7 @@ func TestRole(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
db := factory.Database.MustGet("system")
|
||||
|
||||
test.Error(t, db.Transaction(func() error {
|
||||
userRepo := User(context.Background(), db)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
@@ -19,7 +19,7 @@ func TestUser(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
db := factory.Database.MustGet("system")
|
||||
|
||||
// Run tests in transaction to maintain DB state.
|
||||
test.Error(t, db.Transaction(func() error {
|
||||
|
||||
@@ -3,8 +3,8 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/internal/rand"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/internal/rand"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
gomail "gopkg.in/mail.v2"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/internal/mail"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/internal/mail"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -68,7 +68,7 @@ var (
|
||||
<tr>
|
||||
<td style="padding:30px;border-top: 1px solid #F3F3F5">
|
||||
<p>If you have any questions, please contact <a href="mailto:{{ .SignatureEmail }}" style="color:#1397CB;">{{ .SignatureEmail }}</a>.</p>
|
||||
<p>We hope you enjoy using Crust!</p>
|
||||
<p>We hope you enjoy using Corteza!</p>
|
||||
<p>Best regards, <br>
|
||||
{{ .SignatureName }}</p>
|
||||
</td>
|
||||
@@ -87,7 +87,7 @@ var (
|
||||
|
||||
// @todo Temporary email template storage
|
||||
emailTemplates = map[string]string{
|
||||
"email-confirmation.en.subject": `[Crust] Confirm your email address`,
|
||||
"email-confirmation.en.subject": `[Corteza] Confirm your email address`,
|
||||
"email-confirmation.en.html": emailTemplateHeader +
|
||||
`<h2 style="color: #1397CB;text-align: center;">Confirm your email address</h2>
|
||||
<p>Hello,</p>
|
||||
@@ -95,7 +95,7 @@ var (
|
||||
<p>You will be logged-in after successful confirmation.</p>` +
|
||||
emailTemplateFooter,
|
||||
|
||||
"password-reset.en.subject": `[Crust] Reset your password`,
|
||||
"password-reset.en.subject": `[Corteza] Reset your password`,
|
||||
"password-reset.en.html": emailTemplateHeader +
|
||||
`<h2 style="color: #1397CB;text-align: center;">Reset your password</h2>
|
||||
<p>Hello,</p>
|
||||
|
||||
@@ -87,8 +87,8 @@ func (s authSettings) Format() map[string]interface{} {
|
||||
}
|
||||
|
||||
switch label {
|
||||
case "crust-iam":
|
||||
label = "Crust Unify"
|
||||
case "corteza-iam":
|
||||
label = "Corteza Unify"
|
||||
case "facebook":
|
||||
label = "Facebook"
|
||||
case "gplus":
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
repomock "github.com/crusttech/crust/system/internal/repository/mocks"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
repomock "github.com/cortezaproject/corteza-server/system/internal/repository/mocks"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
// @todo this mockDB will be probably be used by other tests, move it to some common place
|
||||
|
||||
@@ -18,7 +18,7 @@ func (e serviceError) Error() string {
|
||||
}
|
||||
|
||||
func (e serviceError) String() string {
|
||||
return "crust.system.service." + string(e)
|
||||
return "system.service." + string(e)
|
||||
}
|
||||
|
||||
func (e serviceError) withStack() error {
|
||||
|
||||
@@ -7,25 +7,18 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/namsral/flag"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
systemMigrate "github.com/crusttech/crust/system/db"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
systemMigrate "github.com/cortezaproject/corteza-server/system/db"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
logger.Init(zapcore.DebugLevel)
|
||||
|
||||
dsn := ""
|
||||
flag.StringVar(&dsn, "db-dsn", "crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci", "DSN for database connection")
|
||||
flag.Parse()
|
||||
|
||||
factory.Database.Add("default", dsn)
|
||||
factory.Database.Add("system", dsn)
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
factory.Database.Add("system", os.Getenv("SYSTEM_DB_DSN"))
|
||||
db := factory.Database.MustGet("system")
|
||||
db.Profiler = &factory.Database.ProfilerStdout
|
||||
|
||||
// migrate database schema
|
||||
|
||||
@@ -5,11 +5,9 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -54,9 +52,9 @@ func (svc organisation) With(ctx context.Context) OrganisationService {
|
||||
}
|
||||
|
||||
// log() returns zap's logger with requestID from current context and fields.
|
||||
func (svc organisation) log(fields ...zapcore.Field) *zap.Logger {
|
||||
return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
}
|
||||
// func (svc organisation) log(fields ...zapcore.Field) *zap.Logger {
|
||||
// return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
// }
|
||||
|
||||
func (svc organisation) FindByID(id uint64) (*types.Organisation, error) {
|
||||
// @todo: permission check if current user can read organisation
|
||||
|
||||
@@ -6,11 +6,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -73,9 +71,9 @@ func (svc role) With(ctx context.Context) RoleService {
|
||||
}
|
||||
|
||||
// log() returns zap's logger with requestID from current context and fields.
|
||||
func (svc role) log(fields ...zapcore.Field) *zap.Logger {
|
||||
return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
}
|
||||
// func (svc role) log(fields ...zapcore.Field) *zap.Logger {
|
||||
// return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
// }
|
||||
|
||||
func (svc role) FindByID(roleID uint64) (*types.Role, error) {
|
||||
return svc.findByID(roleID)
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
internalSettings "github.com/crusttech/crust/internal/settings"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -22,7 +22,9 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
permSvc permissionServicer
|
||||
DefaultPermissions permissionServicer
|
||||
DefaultIntSettings internalSettings.Service
|
||||
|
||||
DefaultLogger *zap.Logger
|
||||
|
||||
DefaultAccessControl *accessControl
|
||||
@@ -39,17 +41,17 @@ var (
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) (err error) {
|
||||
intSet := internalSettings.NewService(internalSettings.NewRepository(repository.DB(ctx), "sys_settings"))
|
||||
DefaultIntSettings = internalSettings.NewService(internalSettings.NewRepository(repository.DB(ctx), "sys_settings"))
|
||||
|
||||
DefaultLogger = logger.Default().Named("system.service")
|
||||
|
||||
permSvc = permissions.Service(
|
||||
DefaultPermissions = permissions.Service(
|
||||
ctx,
|
||||
DefaultLogger,
|
||||
permissions.Repository(repository.DB(ctx), "sys_permission_rules"))
|
||||
DefaultAccessControl = AccessControl(permSvc)
|
||||
DefaultAccessControl = AccessControl(DefaultPermissions)
|
||||
|
||||
DefaultSettings = Settings(ctx, intSet)
|
||||
DefaultSettings = Settings(ctx, DefaultIntSettings)
|
||||
|
||||
DefaultUser = User(ctx)
|
||||
DefaultRole = Role(ctx)
|
||||
@@ -68,5 +70,5 @@ func Init(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
func Watchers(ctx context.Context) {
|
||||
permSvc.Watch(ctx)
|
||||
DefaultPermissions.Watch(ctx)
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
internalSettings "github.com/crusttech/crust/internal/settings"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -62,9 +60,9 @@ func (svc settings) With(ctx context.Context) SettingsService {
|
||||
}
|
||||
|
||||
// log() returns zap's logger with requestID from current context and fields.
|
||||
func (svc settings) log(fields ...zapcore.Field) *zap.Logger {
|
||||
return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
}
|
||||
// func (svc settings) log(fields ...zapcore.Field) *zap.Logger {
|
||||
// return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
// }
|
||||
|
||||
func (svc settings) FindByPrefix(prefix string) (vv internalSettings.ValueSet, err error) {
|
||||
if !svc.ac.CanReadSettings(svc.ctx) {
|
||||
|
||||
@@ -6,19 +6,15 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
internalAuth "github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
internalAuth "github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrUserInvalidCredentials = serviceError("UserInvalidCredentials")
|
||||
ErrUserLocked = serviceError("UserLocked")
|
||||
|
||||
uuidLength = 36
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -83,9 +79,9 @@ func (svc user) With(ctx context.Context) UserService {
|
||||
}
|
||||
|
||||
// log() returns zap's logger with requestID from current context and fields.
|
||||
func (svc user) log(fields ...zapcore.Field) *zap.Logger {
|
||||
return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
}
|
||||
// func (svc user) log(fields ...zapcore.Field) *zap.Logger {
|
||||
// return logger.AddRequestID(svc.ctx, svc.logger).With(fields...)
|
||||
// }
|
||||
|
||||
func (svc user) FindByID(ID uint64) (*types.User, error) {
|
||||
if ID == 0 {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
)
|
||||
|
||||
// Provision orchestrates various tasks after deployment
|
||||
//
|
||||
func Provision(ctx context.Context) (err error) {
|
||||
if err = resetDefaultPermissionRules(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// @todo move migration here
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resets default permission rules for compose resources
|
||||
func resetDefaultPermissionRules(ctx context.Context) error {
|
||||
var ac = service.DefaultAccessControl
|
||||
|
||||
return ac.Grant(ctx, ac.DefaultRules()...)
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package rest
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
+5
-5
@@ -7,11 +7,11 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/payload"
|
||||
"github.com/cortezaproject/corteza-server/internal/payload/outgoing"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -42,11 +42,11 @@ func (ctrl ExternalAuth) log(ctx context.Context, fields ...zapcore.Field) *zap.
|
||||
return logger.ContextValue(ctx).Named("external-auth").With(fields...)
|
||||
}
|
||||
|
||||
func (ctrl *ExternalAuth) MountRoutes(r chi.Router) {
|
||||
func (ctrl *ExternalAuth) ApiServerRoutes(r chi.Router) {
|
||||
|
||||
// Make sure we're backwards compatible and redirect /oidc to /auth/external/openid-connect.crust-iam
|
||||
// Make sure we're backwards compatible and redirect /oidc to /auth/external/openid-connect.corteza-iam
|
||||
r.Get("/oidc", func(w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, externalAuthBaseUrl+"/openid-connect.crust-iam", http.StatusMovedPermanently)
|
||||
http.Redirect(w, req, externalAuthBaseUrl+"/openid-connect.corteza-iam", http.StatusMovedPermanently)
|
||||
})
|
||||
|
||||
// Copy provider from path (Chi URL param) to request context and return it
|
||||
|
||||
@@ -5,12 +5,12 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/payload"
|
||||
"github.com/cortezaproject/corteza-server/internal/payload/outgoing"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -23,8 +23,8 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
var _ = chi.URLParam
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
var _ = chi.URLParam
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package request
|
||||
|
||||
//lint:file-ignore U1000 Ignore unused code, part of request pkg toolset
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -9,7 +11,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var truthy = regexp.MustCompile("^\\s*(t(rue)?|y(es)?|1)\\s*$")
|
||||
var truthy = regexp.MustCompile(`^\s*(t(rue)?|y(es)?|1)\s*$`)
|
||||
|
||||
func parseJSONTextWithErr(s string) (types.JSONText, error) {
|
||||
result := &types.JSONText{}
|
||||
@@ -46,7 +48,7 @@ func parseUInt64(s string) uint64 {
|
||||
|
||||
func parseUInt64A(values []string) []uint64 {
|
||||
var result []uint64
|
||||
if values != nil && len(values) > 0 {
|
||||
if len(values) > 0 {
|
||||
for _, val := range values {
|
||||
result = append(result, parseUInt64(val))
|
||||
}
|
||||
|
||||
+4
-4
@@ -5,10 +5,10 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/payload"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
+17
-20
@@ -3,30 +3,27 @@ package rest
|
||||
import (
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/system/rest/handlers"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/handlers"
|
||||
)
|
||||
|
||||
func MountRoutes() func(chi.Router) {
|
||||
// Initialize handers & controllers.
|
||||
return func(r chi.Router) {
|
||||
NewExternalAuth().MountRoutes(r)
|
||||
func MountRoutes(r chi.Router) {
|
||||
NewExternalAuth().ApiServerRoutes(r)
|
||||
|
||||
// Provide raw `/auth` handlers
|
||||
handlers.NewAuth((Auth{}).New()).MountRoutes(r)
|
||||
// Provide raw `/auth` handlers
|
||||
handlers.NewAuth((Auth{}).New()).MountRoutes(r)
|
||||
|
||||
handlers.NewAuthInternal((AuthInternal{}).New()).MountRoutes(r)
|
||||
handlers.NewAuthInternal((AuthInternal{}).New()).MountRoutes(r)
|
||||
|
||||
// Protect all _private_ routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.MiddlewareValidOnly)
|
||||
// Protect all _private_ routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.MiddlewareValidOnly)
|
||||
|
||||
handlers.NewUser(User{}.New()).MountRoutes(r)
|
||||
handlers.NewRole(Role{}.New()).MountRoutes(r)
|
||||
handlers.NewOrganisation(Organisation{}.New()).MountRoutes(r)
|
||||
handlers.NewPermissions(Permissions{}.New()).MountRoutes(r)
|
||||
handlers.NewApplication(Application{}.New()).MountRoutes(r)
|
||||
handlers.NewSettings(Settings{}.New()).MountRoutes(r)
|
||||
})
|
||||
}
|
||||
handlers.NewUser(User{}.New()).MountRoutes(r)
|
||||
handlers.NewRole(Role{}.New()).MountRoutes(r)
|
||||
handlers.NewOrganisation(Organisation{}.New()).MountRoutes(r)
|
||||
handlers.NewPermissions(Permissions{}.New()).MountRoutes(r)
|
||||
handlers.NewApplication(Application{}.New()).MountRoutes(r)
|
||||
handlers.NewSettings(Settings{}.New()).MountRoutes(r)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/internal/settings"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
+3
-3
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/config"
|
||||
"github.com/crusttech/crust/internal/middleware"
|
||||
"github.com/crusttech/crust/system/rest"
|
||||
)
|
||||
|
||||
func Routes(ctx context.Context) *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
middleware.Mount(ctx, r, flags.http)
|
||||
MountRoutes(ctx, r)
|
||||
middleware.MountSystemRoutes(ctx, r, flags.http)
|
||||
return r
|
||||
}
|
||||
|
||||
func MountRoutes(ctx context.Context, r chi.Router) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(
|
||||
auth.DefaultJwtHandler.Verifier(),
|
||||
auth.DefaultJwtHandler.Authenticator(),
|
||||
)
|
||||
|
||||
mountRoutes(r, flags.http, rest.MountRoutes())
|
||||
})
|
||||
}
|
||||
|
||||
func mountRoutes(r chi.Router, opts *config.HTTP, mounts ...func(r chi.Router)) {
|
||||
for _, mount := range mounts {
|
||||
mount(r)
|
||||
}
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
// +build integration-disabled
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/namsral/flag"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
systemRepository "github.com/crusttech/crust/system/internal/repository"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
jsonResponse struct {
|
||||
Error struct {
|
||||
Message string `json:"message"`
|
||||
Trace string `json:"trace,omitempty"`
|
||||
} `json:"error"`
|
||||
}
|
||||
)
|
||||
|
||||
func TestUsers(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// we need to set this due to using Init()
|
||||
os.Setenv("SYSTEM_DB_DSN", "crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci")
|
||||
|
||||
mountFlags("system", Flags)
|
||||
|
||||
// Initialize routes and exit on failure.
|
||||
err := Init(ctx)
|
||||
test.Assert(t, err == nil, "Error initializing: %+v", err)
|
||||
|
||||
jwtSecret := "test-secret"
|
||||
|
||||
jwtAuth, err := auth.JWT(jwtSecret, 600)
|
||||
test.NoError(t, err, "Error initializing: %v")
|
||||
|
||||
routes := Routes(ctx)
|
||||
|
||||
// Send check request with invalid JWT token.
|
||||
{
|
||||
req, err := http.NewRequest("GET", "http://127.0.0.1/auth/check", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"id": "zblj",
|
||||
"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
|
||||
})
|
||||
|
||||
jwtAuth.Encode()
|
||||
|
||||
tokenString, err := token.SignedString([]byte(jwtSecret))
|
||||
test.Assert(t, err == nil, "Error creating JWT token: %+v", err)
|
||||
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: "jwt",
|
||||
Value: tokenString,
|
||||
Domain: ".localhost",
|
||||
Expires: time.Now().Add(time.Hour),
|
||||
HttpOnly: true,
|
||||
MaxAge: 50000,
|
||||
Path: "/auth",
|
||||
})
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
jr, err := decodeJson(resp.Body)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Error.Message == "failed to authorize request: signature is invalid", "Expected error 'failed to authorize request: signature is invalid' got: %+v", jr.Error.Message)
|
||||
}
|
||||
|
||||
// Send "Login" request without parameters.
|
||||
{
|
||||
req, err := http.NewRequest("POST", "http://localhost/auth/login", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
jr, err := decodeJson(resp.Body)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Error.Message == "missing form body", "Expected error 'missing form body' got: %+v", jr.Error.Message)
|
||||
}
|
||||
|
||||
// Send "Login" request with missing user.
|
||||
{
|
||||
jsonStr := `{"username":"test123","password":"test123"}`
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost/auth/login", strings.NewReader(jsonStr))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
jr, err := decodeJson(resp.Body)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Error.Message == "crust.auth.repository.UserNotFound", "Expected error 'crust.auth.repository.UserNotFound' got: %+v", jr.Error.Message)
|
||||
}
|
||||
|
||||
// Create user.
|
||||
user := &systemTypes.User{
|
||||
ID: 1337,
|
||||
Username: "johndoe",
|
||||
}
|
||||
{
|
||||
userAPI := systemRepository.User(context.Background(), nil)
|
||||
_, err := userAPI.Create(user)
|
||||
test.Assert(t, err == nil, "Error when inserting user: %+v", err)
|
||||
}
|
||||
|
||||
// Send "Login" request with existing user.
|
||||
if false {
|
||||
form := url.Values{}
|
||||
form.Add("username", "johndoe")
|
||||
form.Add("password", "johndoe123")
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost/auth/login", strings.NewReader(form.Encode()))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
c := resp.Cookies()
|
||||
test.Assert(t, len(c) == 1, "Expected 1 cookie value, got: %+v", len(c))
|
||||
test.Assert(t, c[0].Value != "", "Expected non empty jwt token, got: %+v", c[0].Value)
|
||||
|
||||
type jsonResponse struct {
|
||||
Response struct {
|
||||
UserID string `json:"userID"`
|
||||
Username string `json:"username"`
|
||||
} `json:"response"`
|
||||
}
|
||||
|
||||
var jr jsonResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&jr)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Response.UserID != "0", "Expected userID not to be 0, got: %+v", jr.Response.UserID)
|
||||
test.Assert(t, jr.Response.Username == "johndoe", "Expected username 'johndoe', got: %+v", jr.Response.Username)
|
||||
|
||||
// Check JWT token after successful login.
|
||||
req, err = http.NewRequest("GET", "http://localhost/auth/check", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
routes.ServeHTTP(recorder, req)
|
||||
|
||||
resp = recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
test.Assert(t, resp.StatusCode == 200, "Expected http status code 200, got: %+v", resp.StatusCode)
|
||||
test.Assert(t, len(c) == 1, "Expected 1 cookie value, got: %+v", len(c))
|
||||
test.Assert(t, c[0].Value != "", "Expected non empty jwt token, got: %+v", c[0].Value)
|
||||
}
|
||||
|
||||
// Send "Login" request with existing user.
|
||||
{
|
||||
jsonStr := `{"username": "johndoe", "password": "johndoe123"}`
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost/auth/login", strings.NewReader(jsonStr))
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
c := resp.Cookies()
|
||||
test.Assert(t, len(c) == 1, "Expected 1 cookie value, got: %+v", len(c))
|
||||
test.Assert(t, c[0].Value != "", "Expected non empty jwt token, got: %+v", c[0].Value)
|
||||
|
||||
type jsonResponse struct {
|
||||
Response struct {
|
||||
UserID string `json:"userID"`
|
||||
Username string `json:"username"`
|
||||
} `json:"response"`
|
||||
}
|
||||
|
||||
var jr jsonResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&jr)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Response.UserID != "0", "Expected userID not to be 0, got: %+v", jr.Response.UserID)
|
||||
test.Assert(t, jr.Response.Username == "johndoe", "Expected username 'johndoe', got: %+v", jr.Response.Username)
|
||||
|
||||
// Check JWT token after successful login.
|
||||
req, err = http.NewRequest("GET", "http://localhost/auth/check", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
routes.ServeHTTP(recorder, req)
|
||||
|
||||
resp = recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
test.Assert(t, resp.StatusCode == 200, "Expected http status code 200, got: %+v", resp.StatusCode)
|
||||
test.Assert(t, len(c) == 1, "Expected 1 cookie value, got: %+v", len(c))
|
||||
test.Assert(t, c[0].Value != "", "Expected non empty jwt token, got: %+v", c[0].Value)
|
||||
}
|
||||
|
||||
// Send "Logout" request and expect empty jwt token.
|
||||
{
|
||||
req, err := http.NewRequest("GET", "http://localhost/auth/logout", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
c := resp.Cookies()
|
||||
|
||||
test.Assert(t, resp.StatusCode == 200, "Expected http status code 200, got: %+v", resp.StatusCode)
|
||||
test.Assert(t, len(c) == 1, "Expected 1 cookie value, got: %+v", len(c))
|
||||
test.Assert(t, c[0].Value == "", "Expected empty jwt token, got: %+v", c[0].Value)
|
||||
}
|
||||
|
||||
// Send check request without JWT token.
|
||||
{
|
||||
req, err := http.NewRequest("GET", "http://127.0.0.1/auth/check", nil)
|
||||
test.Assert(t, err == nil, "Error creating request: %+v", err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
routes.ServeHTTP(recorder, req)
|
||||
|
||||
resp := recorder.Result()
|
||||
|
||||
fmt.Println(">>> (request)")
|
||||
fmt.Println(request(req))
|
||||
fmt.Println("----")
|
||||
fmt.Println("<<< (response)")
|
||||
fmt.Println(response(resp))
|
||||
|
||||
jr, err := decodeJson(resp.Body)
|
||||
test.Assert(t, err == nil, "Error decoding response body: %+v", err)
|
||||
test.Assert(t, jr.Error.Message == "http: named cookie not present", "Expected error 'http: named cookie not present' got: %+v", jr.Error.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func request(req *http.Request) string {
|
||||
b, err := httputil.DumpRequestOut(req, true)
|
||||
if err != nil {
|
||||
return ">>> Error: " + err.Error()
|
||||
}
|
||||
if b != nil {
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func response(resp *http.Response) string {
|
||||
b, err := httputil.DumpResponse(resp, true)
|
||||
if err != nil {
|
||||
return "<<< Error: " + err.Error()
|
||||
}
|
||||
if b != nil {
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func mountFlags(prefix string, mountFlags ...func(...string)) {
|
||||
for _, mount := range mountFlags {
|
||||
mount(prefix)
|
||||
}
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func decodeJson(r io.Reader) (jsonResponse, error) {
|
||||
var ret jsonResponse
|
||||
err := json.NewDecoder(r).Decode(&ret)
|
||||
if err != nil {
|
||||
return jsonResponse{}, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) error {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/crusttech/crust/system/internal/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/db"
|
||||
"github.com/crusttech/crust/internal/logger"
|
||||
"github.com/crusttech/crust/internal/mail"
|
||||
"github.com/crusttech/crust/internal/metrics"
|
||||
"github.com/crusttech/crust/internal/settings"
|
||||
migrate "github.com/crusttech/crust/system/db"
|
||||
"github.com/crusttech/crust/system/internal/auth/external"
|
||||
"github.com/crusttech/crust/system/internal/repository"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
func Init(ctx context.Context) (err error) {
|
||||
// validate configuration
|
||||
if err = flags.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
mail.SetupDialer(flags.smtp)
|
||||
|
||||
if err = InitDatabase(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if flags.http.ClientTSLInsecure {
|
||||
// This will allow HTTPS requests to insecure hosts (expired, wrong host, self signed, untrusted root...)
|
||||
// With this enabled, features like OIDC auto-discovery should work on any of examples found on badssl.com.
|
||||
//
|
||||
// With SYSTEM_HTTP_CLIENT_TSL_INSECURE=0 (default) next command returns 404 error (expected)
|
||||
// > ./system-cli external-auth auto-discovery foo-tsl-1 https://expired.badssl.com/
|
||||
//
|
||||
// Without SYSTEM_HTTP_CLIENT_TSL_INSECURE=1 next command returns "x509: certificate has expired or is not yet valid"
|
||||
// > ./system-cli external-auth auto-discovery foo-tsl-1 https://expired.badssl.com/
|
||||
//
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
// configure resputil options
|
||||
resputil.SetConfig(resputil.Options{
|
||||
Pretty: flags.http.Pretty,
|
||||
Trace: flags.http.Tracing,
|
||||
Logger: func(err error) {
|
||||
// @todo: error logging
|
||||
},
|
||||
})
|
||||
|
||||
// Use JWT secret for hmac signer for now
|
||||
auth.DefaultSigner = auth.HmacSigner(flags.jwt.Secret)
|
||||
auth.DefaultJwtHandler, err = auth.JWT(flags.jwt.Secret, flags.jwt.Expiry)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Don't change this, it needs database connection
|
||||
if err = service.Init(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func InitDatabase(ctx context.Context) error {
|
||||
// start/configure database connection
|
||||
db, err := db.TryToConnect(ctx, "system", flags.db.DSN, flags.db.Profiler)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not connect to database")
|
||||
}
|
||||
|
||||
// migrate database schema
|
||||
if err := migrate.Migrate(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func StartWatchers(ctx context.Context) {
|
||||
service.Watchers(ctx)
|
||||
}
|
||||
|
||||
func StartRestAPI(ctx context.Context) error {
|
||||
// Load settings from the database,
|
||||
// for now, only at start-up time.
|
||||
settingService := settings.NewService(settings.NewRepository(repository.DB(ctx), "sys_settings")).With(ctx)
|
||||
|
||||
// Setup goth/external authentication
|
||||
external.Init(settingService)
|
||||
|
||||
logger.Default().Info("Starting HTTP server", zap.String("address", flags.http.Addr))
|
||||
listener, err := net.Listen("tcp", flags.http.Addr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("Can't listen on addr %s", flags.http.Addr))
|
||||
}
|
||||
|
||||
if flags.monitor.Interval > 0 {
|
||||
go metrics.NewMonitor(flags.monitor.Interval)
|
||||
}
|
||||
|
||||
go http.Serve(listener, Routes(ctx))
|
||||
<-ctx.Done()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/db"
|
||||
"github.com/cortezaproject/corteza-server/internal/logger"
|
||||
"github.com/cortezaproject/corteza-server/pkg/api"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/flags"
|
||||
"github.com/cortezaproject/corteza-server/system/commands"
|
||||
migrate "github.com/cortezaproject/corteza-server/system/db"
|
||||
"github.com/cortezaproject/corteza-server/system/internal/service"
|
||||
"github.com/cortezaproject/corteza-server/system/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
system = "system"
|
||||
)
|
||||
|
||||
type (
|
||||
System struct {
|
||||
log *zap.Logger
|
||||
|
||||
// General
|
||||
logOpt *flags.LogOpt
|
||||
smtpOpt *flags.SMTPOpt
|
||||
jwtOpt *flags.JWTOpt
|
||||
httpClientOpt *flags.HttpClientOpt
|
||||
|
||||
// System specific
|
||||
dbOpt *flags.DBOpt
|
||||
provisionOpt *flags.ProvisionOpt
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
logger.Init(zap.DebugLevel)
|
||||
}
|
||||
|
||||
func InitSystem() *System {
|
||||
return &System{
|
||||
log: logger.Default().Named(system),
|
||||
}
|
||||
}
|
||||
|
||||
// Command produces cobra.Command
|
||||
func (m *System) Command(ctx context.Context) (cmd *cobra.Command) {
|
||||
cmd = &cobra.Command{
|
||||
Use: "corteza-server-system",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
cli.InitGeneralServices(m.logOpt, m.smtpOpt, m.jwtOpt, m.httpClientOpt)
|
||||
|
||||
return m.StartServices(ctx)
|
||||
},
|
||||
}
|
||||
|
||||
m.BindGlobalFlags(cmd)
|
||||
|
||||
srv := api.NewServer(m.log)
|
||||
serveApiCmd := srv.Command(ctx, system, m.ApiServerPreRun)
|
||||
|
||||
// Bind all flags we need for serving system
|
||||
m.BindApiServerFlags(serveApiCmd)
|
||||
|
||||
srv.MountRoutes(m.ApiServerRoutes)
|
||||
|
||||
cmd.AddCommand(
|
||||
serveApiCmd,
|
||||
cli.SetupProvisionSubcommands(ctx, m),
|
||||
)
|
||||
|
||||
m.AddCommands(cmd, ctx)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddCommands - other commands that this subservice needs
|
||||
func (m *System) AddCommands(cmd *cobra.Command, ctx context.Context) {
|
||||
cmd.AddCommand(
|
||||
commands.Settings(ctx),
|
||||
commands.Auth(ctx),
|
||||
commands.Users(ctx),
|
||||
commands.Roles(ctx),
|
||||
)
|
||||
}
|
||||
|
||||
// Binds all global flags
|
||||
func (m *System) BindGlobalFlags(cmd *cobra.Command) {
|
||||
m.logOpt = flags.Log(cmd)
|
||||
m.smtpOpt = flags.SMTP(cmd)
|
||||
m.jwtOpt = flags.JWT(cmd)
|
||||
m.httpClientOpt = flags.HttpClient(cmd)
|
||||
}
|
||||
|
||||
// BindApiServerFlags sets & binds all API server flags
|
||||
func (m *System) BindApiServerFlags(cmd *cobra.Command) {
|
||||
m.dbOpt = flags.DB(cmd, system)
|
||||
m.provisionOpt = flags.Provision(cmd, system)
|
||||
}
|
||||
|
||||
func (m *System) StartServices(ctx context.Context) (err error) {
|
||||
_, err = db.TryToConnect(ctx, m.log, system, m.dbOpt.DSN, m.dbOpt.Profiler)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not connect to database")
|
||||
}
|
||||
|
||||
if m.provisionOpt.Database {
|
||||
err = m.ProvisionMigrateDatabase(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = service.Init(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ApiServerPreRun is executed before serve-api command runs REST API server
|
||||
//
|
||||
// Should initialize all that needs to run in the background
|
||||
func (m System) ApiServerPreRun(ctx context.Context) error {
|
||||
service.DefaultPermissions.Watch(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApiServerRoutes mounts api server routes
|
||||
func (m *System) ApiServerRoutes(r chi.Router) {
|
||||
rest.MountRoutes(r)
|
||||
}
|
||||
|
||||
// ProvisionMigrateDatabase migrates database to new version
|
||||
//
|
||||
// This is ran by default on serve-api (when not explicitly disabled with --compose-provision-database=false)
|
||||
// or on demand with "provision migrate-database"
|
||||
func (m System) ProvisionMigrateDatabase(ctx context.Context) error {
|
||||
var db, err = factory.Database.Get(system)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db = db.With(ctx)
|
||||
// Disable profiler for migrations
|
||||
db.Profiler = nil
|
||||
|
||||
return migrate.Migrate(db)
|
||||
}
|
||||
|
||||
// ProvisionAccessControl resets access-control rules for roles admin (2) and everyone (1)
|
||||
//
|
||||
// Run with emand with "provision access-control-rules"
|
||||
func (m System) ProvisionAccessControl(ctx context.Context) error {
|
||||
var ac = service.DefaultAccessControl
|
||||
return ac.Grant(ctx, ac.DefaultRules()...)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
// Hello! This file is auto-generated.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -44,6 +44,7 @@ func (a Application) PermissionResource() permissions.Resource {
|
||||
}
|
||||
|
||||
func (au *ApplicationUnify) Scan(value interface{}) error {
|
||||
//lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8
|
||||
switch value.(type) {
|
||||
case nil:
|
||||
au = nil
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
// Hello! This file is auto-generated.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
// Hello! This file is auto-generated.
|
||||
|
||||
@@ -3,7 +3,7 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
const SystemPermissionResource = permissions.Resource("system")
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
// Hello! This file is auto-generated.
|
||||
|
||||
@@ -3,7 +3,7 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/test"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
// Hello! This file is auto-generated.
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -54,7 +54,7 @@ type (
|
||||
|
||||
const (
|
||||
NormalUser UserKind = ""
|
||||
BotUser = "bot"
|
||||
BotUser UserKind = "bot"
|
||||
)
|
||||
|
||||
func (u *User) Valid() bool {
|
||||
@@ -79,6 +79,7 @@ func (u *User) PermissionResource() permissions.Resource {
|
||||
}
|
||||
|
||||
func (meta *UserMeta) Scan(value interface{}) error {
|
||||
//lint:ignore S1034 This typecast is intentional, we need to get []byte out of a []uint8
|
||||
switch value.(type) {
|
||||
case nil:
|
||||
*meta = UserMeta{}
|
||||
|
||||
Reference in New Issue
Block a user