Added default user option and user control
This commit is contained in:
@@ -7,6 +7,11 @@ APP_DOWNLOAD_LOCATION=https://github.com/frikky/shuffle-apps
|
|||||||
APP_DOWNLOAD_AUTH_USERNAME=""
|
APP_DOWNLOAD_AUTH_USERNAME=""
|
||||||
APP_DOWNLOAD_AUTH_PASSWORD=""
|
APP_DOWNLOAD_AUTH_PASSWORD=""
|
||||||
|
|
||||||
|
# User config for first load
|
||||||
|
SHUFFLE_DEFAULT_USERNAME=""
|
||||||
|
SHUFFLE_DEFAULT_PASSWORD=""
|
||||||
|
SHUFFLE_DEFAULT_APIKEY=""
|
||||||
|
|
||||||
# Local location of your app directory. Can't use ~/
|
# Local location of your app directory. Can't use ~/
|
||||||
APP_HOTLOAD_LOCATION=./shuffle-apps
|
APP_HOTLOAD_LOCATION=./shuffle-apps
|
||||||
|
|
||||||
|
|||||||
+209
-216
@@ -995,6 +995,119 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write([]byte(`{"success": true}`))
|
resp.Write([]byte(`{"success": true}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createNewUser(username, password, role, apikey string) error {
|
||||||
|
// Returns false if there is an issue
|
||||||
|
// Use this for register
|
||||||
|
err := checkPasswordStrength(password)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Bad password strength: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = checkUsername(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Bad Username strength: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
q := datastore.NewQuery("Users").Filter("Username =", username)
|
||||||
|
var users []User
|
||||||
|
_, err = dbclient.GetAll(ctx, q, &users)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed getting user for registration: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
return errors.New(fmt.Sprintf("Username %s already exists", username))
|
||||||
|
}
|
||||||
|
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 8)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Wrong password for %s: %s", username, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newUser := new(User)
|
||||||
|
newUser.Username = username
|
||||||
|
newUser.Password = string(hashedPassword)
|
||||||
|
newUser.Verified = false
|
||||||
|
newUser.CreationTime = time.Now().Unix()
|
||||||
|
newUser.Active = true
|
||||||
|
newUser.Orgs = []string{"default"}
|
||||||
|
|
||||||
|
// FIXME - Remove this later
|
||||||
|
if role == "admin" {
|
||||||
|
newUser.Role = "admin"
|
||||||
|
newUser.Roles = []string{"admin"}
|
||||||
|
} else {
|
||||||
|
newUser.Role = "user"
|
||||||
|
newUser.Roles = []string{"user"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(apikey) > 0 {
|
||||||
|
newUser.ApiKey = apikey
|
||||||
|
}
|
||||||
|
|
||||||
|
// set limits
|
||||||
|
newUser.Limits.DailyApiUsage = 100
|
||||||
|
newUser.Limits.DailyWorkflowExecutions = 1000
|
||||||
|
newUser.Limits.DailyCloudExecutions = 100
|
||||||
|
newUser.Limits.DailyTriggers = 20
|
||||||
|
newUser.Limits.DailyMailUsage = 100
|
||||||
|
newUser.Limits.MaxTriggers = 10
|
||||||
|
newUser.Limits.MaxWorkflows = 10
|
||||||
|
|
||||||
|
// Set base info for the user
|
||||||
|
newUser.Executions.TotalApiUsage = 0
|
||||||
|
newUser.Executions.TotalWorkflowExecutions = 0
|
||||||
|
newUser.Executions.TotalAppExecutions = 0
|
||||||
|
newUser.Executions.TotalCloudExecutions = 0
|
||||||
|
newUser.Executions.TotalOnpremExecutions = 0
|
||||||
|
newUser.Executions.DailyApiUsage = 0
|
||||||
|
newUser.Executions.DailyWorkflowExecutions = 0
|
||||||
|
newUser.Executions.DailyAppExecutions = 0
|
||||||
|
newUser.Executions.DailyCloudExecutions = 0
|
||||||
|
newUser.Executions.DailyOnpremExecutions = 0
|
||||||
|
|
||||||
|
verifyToken := uuid.NewV4()
|
||||||
|
ID := uuid.NewV4()
|
||||||
|
newUser.Id = ID.String()
|
||||||
|
newUser.VerificationToken = verifyToken.String()
|
||||||
|
err = setUser(ctx, newUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error adding User %s: %s", username, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
url := fmt.Sprintf("https://shuffler.io/register/%s", verifyToken.String())
|
||||||
|
const verifyMessage = `
|
||||||
|
Registration URL :)
|
||||||
|
|
||||||
|
%s
|
||||||
|
`
|
||||||
|
addr := newUser.Username
|
||||||
|
|
||||||
|
msg := &mail.Message{
|
||||||
|
Sender: "Shuffle <frikky@shuffler.io>",
|
||||||
|
To: []string{addr},
|
||||||
|
Subject: "Verify your username - Shuffle",
|
||||||
|
Body: fmt.Sprintf(verifyMessage, url),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println(msg.Body)
|
||||||
|
if err := mail.Send(ctx, msg); err != nil {
|
||||||
|
log.Printf("Couldn't send email: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = increaseStatisticsField(ctx, "successful_register", username, 1)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to increase total apps loaded stats: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -1030,128 +1143,21 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns false if there is an issue
|
role := "user"
|
||||||
// Use this for register
|
|
||||||
err = checkPasswordStrength(data.Password)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Bad password strength: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = checkUsername(data.Username)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Bad Username strength: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
q := datastore.NewQuery("Users").Filter("Username =", data.Username)
|
|
||||||
var users []User
|
|
||||||
_, err = dbclient.GetAll(ctx, q, &users)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed getting user for registration: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed getting username"}`)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(users) > 0 {
|
|
||||||
log.Printf("Username %s exists and can't register", data.Username)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(data.Password), 8)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Wrong password for %s: %s", data.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
newUser := new(User)
|
|
||||||
newUser.Username = data.Username
|
|
||||||
newUser.Password = string(hashedPassword)
|
|
||||||
newUser.Verified = false
|
|
||||||
newUser.CreationTime = time.Now().Unix()
|
|
||||||
newUser.Active = true
|
|
||||||
newUser.Orgs = []string{"default"}
|
|
||||||
|
|
||||||
// FIXME - Remove this later
|
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
newUser.Role = "admin"
|
role = "admin"
|
||||||
newUser.Roles = []string{"admin"}
|
|
||||||
} else {
|
|
||||||
newUser.Role = "user"
|
|
||||||
newUser.Roles = []string{"user"}
|
|
||||||
}
|
}
|
||||||
|
err = createNewUser(data.Username, data.Password, role, "")
|
||||||
// set limits
|
|
||||||
newUser.Limits.DailyApiUsage = 100
|
|
||||||
newUser.Limits.DailyWorkflowExecutions = 1000
|
|
||||||
newUser.Limits.DailyCloudExecutions = 100
|
|
||||||
newUser.Limits.DailyTriggers = 20
|
|
||||||
newUser.Limits.DailyMailUsage = 100
|
|
||||||
newUser.Limits.MaxTriggers = 10
|
|
||||||
newUser.Limits.MaxWorkflows = 10
|
|
||||||
|
|
||||||
// Set base info for the user
|
|
||||||
newUser.Executions.TotalApiUsage = 0
|
|
||||||
newUser.Executions.TotalWorkflowExecutions = 0
|
|
||||||
newUser.Executions.TotalAppExecutions = 0
|
|
||||||
newUser.Executions.TotalCloudExecutions = 0
|
|
||||||
newUser.Executions.TotalOnpremExecutions = 0
|
|
||||||
newUser.Executions.DailyApiUsage = 0
|
|
||||||
newUser.Executions.DailyWorkflowExecutions = 0
|
|
||||||
newUser.Executions.DailyAppExecutions = 0
|
|
||||||
newUser.Executions.DailyCloudExecutions = 0
|
|
||||||
newUser.Executions.DailyOnpremExecutions = 0
|
|
||||||
|
|
||||||
addr := newUser.Username
|
|
||||||
|
|
||||||
verifyToken := uuid.NewV4()
|
|
||||||
ID := uuid.NewV4()
|
|
||||||
newUser.Id = ID.String()
|
|
||||||
newUser.VerificationToken = verifyToken.String()
|
|
||||||
err = setUser(ctx, newUser)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error adding User %s: %s", data.Username, err)
|
log.Printf("Failed registering user: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("https://shuffler.io/register/%s", verifyToken.String())
|
|
||||||
const verifyMessage = `
|
|
||||||
Registration URL :)
|
|
||||||
|
|
||||||
%s
|
|
||||||
`
|
|
||||||
|
|
||||||
msg := &mail.Message{
|
|
||||||
Sender: "Shuffle <frikky@shuffler.io>",
|
|
||||||
To: []string{addr},
|
|
||||||
Subject: "Verify your username - Shuffle",
|
|
||||||
Body: fmt.Sprintf(verifyMessage, url),
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(msg.Body)
|
|
||||||
if err := mail.Send(ctx, msg); err != nil {
|
|
||||||
log.Printf("Couldn't send email: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(`{"success": true}`))
|
resp.Write([]byte(`{"success": true}`))
|
||||||
log.Printf("%s Successfully registered.", data.Username)
|
log.Printf("%s Successfully registered.", data.Username)
|
||||||
|
|
||||||
err = increaseStatisticsField(ctx, "successful_register", data.Username, 1)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to increase total apps loaded stats: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCookie(request *http.Request) bool {
|
func handleCookie(request *http.Request) bool {
|
||||||
@@ -1285,56 +1291,73 @@ func handleApiGeneration(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := request.Cookie("session_token")
|
userInfo, err := handleApiAuthentication(resp, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("User doesn't have sessiontoken, on apigen: %s", err)
|
log.Printf("Api authentication failed in apigen: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("APIKEY")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
sessionToken := c.Value
|
if request.Method == "GET" {
|
||||||
session, err := getSession(ctx, sessionToken)
|
newUserInfo, err := generateApikey(ctx, userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Session %#v doesn't exist (api gen): %s", session, err)
|
log.Printf("Failed to generate apikey for user %s: %s", userInfo.Username, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
userInfo = newUserInfo
|
||||||
|
log.Printf("Updated apikey for user %s", userInfo.Username)
|
||||||
|
} else if request.Method == "POST" {
|
||||||
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed reading body")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Missing field: user_id"}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type userId struct {
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var t userId
|
||||||
|
err = json.Unmarshal(body, &t)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed unmarshaling userId: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unmarshaling. Missing field: user_id"}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if userInfo.Role != "admin" {
|
||||||
|
log.Printf("%s tried and failed to change apikey for %s", userInfo.Username, t.UserId)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "You need to be admin to change others' apikey"}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
foundUser, err := getUser(ctx, t.UserId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Can't find user %s (apikey gen)", t.UserId, err)
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newUserInfo, err := generateApikey(ctx, *foundUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to generate apikey for user %s: %s", foundUser.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
foundUser = &newUserInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get session first
|
|
||||||
// Should basically never happen
|
|
||||||
userInfo, err := getUser(ctx, session.Id)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (apigen): %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete old apikey from cache
|
|
||||||
//memcache.Delete(ctx, userInfo.ApiKey)
|
|
||||||
|
|
||||||
if session.Session != userInfo.Session {
|
|
||||||
log.Printf("Session %s is not the latest. %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
newUserInfo, err := generateApikey(ctx, *userInfo)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to generate apikey for user %s: %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userInfo = &newUserInfo
|
|
||||||
|
|
||||||
//memcache.Delete(request.Context(), sessionToken)
|
|
||||||
|
|
||||||
log.Printf("Updated apikey for user %s", userInfo.Username)
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, userInfo.Username, userInfo.Verified, userInfo.ApiKey)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, userInfo.Username, userInfo.Verified, userInfo.ApiKey)))
|
||||||
}
|
}
|
||||||
@@ -1345,44 +1368,16 @@ func handleSettings(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := request.Cookie("session_token")
|
userInfo, err := handleApiAuthentication(resp, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("User doesn't have sessiontoken, on getsettings: %s", err)
|
log.Printf("Api authentication failed in apigen: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
sessionToken := c.Value
|
|
||||||
session, err := getSession(ctx, sessionToken)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Session %#v doesn't exist (settings): %s", session, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get session first
|
|
||||||
// Should basically never happen
|
|
||||||
UserInfo, err := getUser(ctx, session.Id)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (settings): %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("%s %s", session.Session, UserInfo.Session)
|
|
||||||
if session.Session != UserInfo.Session {
|
|
||||||
log.Printf("Session %s is not the latest. %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, UserInfo.Username, UserInfo.Verified, UserInfo.ApiKey)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, userInfo.Username, userInfo.Verified, userInfo.ApiKey)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -1391,21 +1386,16 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should compare with local storage first
|
userInfo, err := handleApiAuthentication(resp, request)
|
||||||
c, err := request.Cookie("session_token")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in handleInfo: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME - check memcache here
|
|
||||||
// Get the item from the memcache
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
session, err := getSession(ctx, userInfo.Session)
|
||||||
sessionToken := c.Value
|
|
||||||
//log.Printf("Found session %s", sessionToken)
|
|
||||||
session, err := getSession(ctx, sessionToken)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Session %#v doesn't exist: %s", session, err)
|
log.Printf("Session %#v doesn't exist: %s", session, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
@@ -1413,17 +1403,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get session first
|
// This is a long check to see if an inactive admin can access the site
|
||||||
// Should basically never happen
|
|
||||||
userInfo, err := getUser(ctx, session.Id)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (info): %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a long check to see if an inactive admin can access the portal
|
|
||||||
if !userInfo.Active {
|
if !userInfo.Active {
|
||||||
if userInfo.Role == "admin" {
|
if userInfo.Role == "admin" {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -1478,7 +1458,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
//log.Printf("%s %s", session.Session, UserInfo.Session)
|
//log.Printf("%s %s", session.Session, UserInfo.Session)
|
||||||
if session.Session != userInfo.Session {
|
if session.Session != userInfo.Session {
|
||||||
log.Printf("Session %s is not the latest. %s", session.Username, err)
|
log.Printf("Session %s is not the same as %s for %s. %s", userInfo.Session, session.Session, userInfo.Username, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
||||||
return
|
return
|
||||||
@@ -5966,18 +5946,18 @@ func runInit(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fix active users etc
|
// Fix active users etc
|
||||||
log.Printf("Reformatting users")
|
log.Printf("Checking users")
|
||||||
q := datastore.NewQuery("Users").Filter("active =", true)
|
q := datastore.NewQuery("Users").Filter("active =", true)
|
||||||
var users []User
|
var activeusers []User
|
||||||
_, err = dbclient.GetAll(ctx, q, &users)
|
_, err = dbclient.GetAll(ctx, q, &activeusers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting users apikey (runinit): %s", err)
|
log.Printf("Error getting users during init: %s", err)
|
||||||
} else {
|
} else {
|
||||||
if len(users) == 0 {
|
q := datastore.NewQuery("Users")
|
||||||
|
var users []User
|
||||||
|
_, err := dbclient.GetAll(ctx, q, &users)
|
||||||
|
if len(activeusers) == 0 && len(users) > 0 {
|
||||||
log.Printf("No active users found - setting ALL to active")
|
log.Printf("No active users found - setting ALL to active")
|
||||||
q := datastore.NewQuery("Users")
|
|
||||||
var users []User
|
|
||||||
_, err := dbclient.GetAll(ctx, q, &users)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
user.Active = true
|
user.Active = true
|
||||||
@@ -6006,6 +5986,19 @@ func runInit(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if len(users) == 0 {
|
||||||
|
log.Printf("Trying to set up user based on environments DEFAULT_USERNAME & DEFAULT_PASSWORD")
|
||||||
|
username := os.Getenv("SHUFFLE_DEFAULT_USERNAME")
|
||||||
|
password := os.Getenv("SHUFFLE_DEFAULT_PASSWORD")
|
||||||
|
if len(username) == 0 || len(password) == 0 {
|
||||||
|
log.Printf("DEFAULT_USERNAME and DEFAULT_PASSWORD not defined as environments. Running without default user.")
|
||||||
|
} else {
|
||||||
|
apikey := os.Getenv("SHUFFLE_DEFAULT_APIKEY")
|
||||||
|
err = createNewUser(username, password, "admin", apikey)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to create default user %s: %s", username, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6175,7 +6168,7 @@ func init() {
|
|||||||
r.HandleFunc("/api/v1/getusers", handleGetUsers).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/getusers", handleGetUsers).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/getinfo", handleInfo).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/getinfo", handleInfo).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/getsettings", handleSettings).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/getsettings", handleSettings).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/generateapikey", handleApiGeneration).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/generateapikey", handleApiGeneration).Methods("GET", "POST", "OPTIONS")
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/getenvironments", handleGetEnvironments).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/getenvironments", handleGetEnvironments).Methods("GET", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/setenvironments", handleSetEnvironments).Methods("PUT", "OPTIONS")
|
r.HandleFunc("/api/v1/setenvironments", handleSetEnvironments).Methods("PUT", "OPTIONS")
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ services:
|
|||||||
- DATASTORE_EMULATOR_HOST=shuffle-database:8000
|
- DATASTORE_EMULATOR_HOST=shuffle-database:8000
|
||||||
- APP_DOWNLOAD_LOCATION=${APP_DOWNLOAD_LOCATION}
|
- APP_DOWNLOAD_LOCATION=${APP_DOWNLOAD_LOCATION}
|
||||||
- APP_HOTLOAD_FOLDER=/shuffle-apps
|
- APP_HOTLOAD_FOLDER=/shuffle-apps
|
||||||
|
- SHUFFLE_DEFAULT_USERNAME=${SHUFFLE_DEFAULT_USERNAME}
|
||||||
|
- SHUFFLE_DEFAULT_PASSWORD=${SHUFFLE_DEFAULT_PASSWORD}
|
||||||
|
- SHUFFLE_DEFAULT_APIKEY=${SHUFFLE_DEFAULT_APIKEY}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
|
|||||||
@@ -319,14 +319,17 @@ const Admin = (props) => {
|
|||||||
modalUser[field] = value
|
modalUser[field] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateApikey = () => {
|
const generateApikey = (userId) => {
|
||||||
|
const data = {"user_id": userId}
|
||||||
|
|
||||||
fetch(globalUrl+"/api/v1/generateapikey", {
|
fetch(globalUrl+"/api/v1/generateapikey", {
|
||||||
method: 'GET',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
credentials: "include",
|
body: JSON.stringify(data),
|
||||||
|
credentials: "include",
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
@@ -407,7 +410,7 @@ const Admin = (props) => {
|
|||||||
style={{}}
|
style={{}}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => generateApikey(selectedUser)}
|
onClick={() => generateApikey(selectedUser.id)}
|
||||||
>
|
>
|
||||||
Get new API key
|
Get new API key
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -845,6 +845,7 @@ const AngularWorkflow = (props) => {
|
|||||||
setRightSideBarOpen(true)
|
setRightSideBarOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks for errors in edges when they're added
|
||||||
const onEdgeAdded = (event) => {
|
const onEdgeAdded = (event) => {
|
||||||
setLastSaved(false)
|
setLastSaved(false)
|
||||||
const edge = event.target.data()
|
const edge = event.target.data()
|
||||||
@@ -856,18 +857,13 @@ const AngularWorkflow = (props) => {
|
|||||||
var found = false
|
var found = false
|
||||||
for (var key in workflow.branches) {
|
for (var key in workflow.branches) {
|
||||||
if (workflow.branches[key].destination_id === edge.source && workflow.branches[key].source_id === edge.target) {
|
if (workflow.branches[key].destination_id === edge.source && workflow.branches[key].source_id === edge.target) {
|
||||||
alert.error("A pointer in the opposite direction already exists")
|
alert.error("A branch in the opposite direction already exists")
|
||||||
event.target.remove()
|
event.target.remove()
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
} else if (workflow.branches[key].destination_id === edge.target && workflow.branches[key].source_id === edge.source) {
|
} else if (workflow.branches[key].destination_id === edge.target && workflow.branches[key].source_id === edge.source) {
|
||||||
// Checks if NOT trigger
|
alert.error("That branch already exists")
|
||||||
//workflow.triggers.find(data => data.id === workflow.branches[key].source_id).length === 0)
|
event.target.remove()
|
||||||
const triggercheck = workflow.triggers.find(data => data.id === workflow.branches[key].source_id)
|
|
||||||
if (workflow.triggers !== undefined && triggercheck !== undefined && triggercheck.length === 0) {
|
|
||||||
alert.error("That pointer already exists")
|
|
||||||
event.target.remove()
|
|
||||||
}
|
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
} else if (edge.target === workflow.start) {
|
} else if (edge.target === workflow.start) {
|
||||||
@@ -878,16 +874,29 @@ const AngularWorkflow = (props) => {
|
|||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} else if (edge.source === workflow.branches[key].source_id) {
|
||||||
|
// FIXME: Verify multi-target for triggers
|
||||||
|
// 1. Check if destination exists
|
||||||
|
// 2. Check if source is a trigger
|
||||||
|
// targetnode = workflow.triggers.findIndex(data => data.id === edge.source)
|
||||||
|
// console.log("Destination: ", edge.target)
|
||||||
|
// console.log("CHECK SOURCE IF ITS A TRIGGER: ", targetnode)
|
||||||
|
// if (targetnode !== -1) {
|
||||||
|
// alert.error("Triggers can only target one target (startnode)")
|
||||||
|
// event.target.remove()
|
||||||
|
// found = true
|
||||||
|
// break
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
// Find the targetnode and check if its a trigger
|
// Find the targetnode and check if its a trigger
|
||||||
// FIXME - do this for both actions and other types?
|
// FIXME - do this for both actions and other types?
|
||||||
//targetnode = workflow.triggers.findIndex(data => data.id === edge.target)
|
targetnode = workflow.triggers.findIndex(data => data.id === edge.target)
|
||||||
//if (targetnode !== -1) {
|
if (targetnode !== -1) {
|
||||||
// alert.error("Can't have triggers as target")
|
alert.error("Can't have triggers as target of branch")
|
||||||
// event.target.remove()
|
event.target.remove()
|
||||||
// found = true
|
found = true
|
||||||
// break
|
break
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -901,10 +910,10 @@ const AngularWorkflow = (props) => {
|
|||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
newbranch["hasErrors"] = false
|
newbranch["hasErrors"] = false
|
||||||
}
|
|
||||||
|
|
||||||
workflow.branches.push(newbranch)
|
workflow.branches.push(newbranch)
|
||||||
setWorkflow(workflow)
|
setWorkflow(workflow)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onNodeAdded = (event) => {
|
const onNodeAdded = (event) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user