Started re-adding oauth2 configurations
This commit is contained in:
+79
-19
@@ -28,6 +28,7 @@ class AppBase:
|
|||||||
self.authorization = os.getenv("AUTHORIZATION", "")
|
self.authorization = os.getenv("AUTHORIZATION", "")
|
||||||
self.current_execution_id = os.getenv("EXECUTIONID", "")
|
self.current_execution_id = os.getenv("EXECUTIONID", "")
|
||||||
self.full_execution = os.getenv("FULL_EXECUTION", "")
|
self.full_execution = os.getenv("FULL_EXECUTION", "")
|
||||||
|
self.start_time = int(time.time())
|
||||||
self.result_wrapper_count = 0
|
self.result_wrapper_count = 0
|
||||||
|
|
||||||
if isinstance(self.action, str):
|
if isinstance(self.action, str):
|
||||||
@@ -482,10 +483,17 @@ class AppBase:
|
|||||||
print(f"NEW PARAMS: {new_params}")
|
print(f"NEW PARAMS: {new_params}")
|
||||||
if len(new_params) == 0:
|
if len(new_params) == 0:
|
||||||
print("[WARNING] SHOULD STOP MULTI-EXECUTION BECAUSE FIELDS AREN'T UNIQUE")
|
print("[WARNING] SHOULD STOP MULTI-EXECUTION BECAUSE FIELDS AREN'T UNIQUE")
|
||||||
action_result["status"] = "SKIPPED"
|
action_result = {
|
||||||
action_result["result"] = f"All values were non-unique"
|
"action": self.action,
|
||||||
action_result["completed_at"] = int(time.time())
|
"authorization": self.authorization,
|
||||||
self.send_result(action_result, headers, stream_path)
|
"execution_id": self.current_execution_id,
|
||||||
|
"result": f"All {len(param_multiplier)} values were non-unique",
|
||||||
|
"started_at": self.start_time,
|
||||||
|
"status": "SKIPPED",
|
||||||
|
"completed_at": int(time.time()),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send_result(action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams")
|
||||||
exit()
|
exit()
|
||||||
#return
|
#return
|
||||||
else:
|
else:
|
||||||
@@ -906,6 +914,41 @@ class AppBase:
|
|||||||
return data.strip()
|
return data.strip()
|
||||||
if "split" in thistype:
|
if "split" in thistype:
|
||||||
return data.split()
|
return data.split()
|
||||||
|
if "join" in thistype:
|
||||||
|
print(f"SHOULD JOIN: {data}")
|
||||||
|
try:
|
||||||
|
splitvalues = data.split(",")
|
||||||
|
if "," not in data:
|
||||||
|
return f"join({data})"
|
||||||
|
|
||||||
|
if len(splitvalues) >= 2:
|
||||||
|
print(f"SPLITVALUE: {splitvalues[-1]}")
|
||||||
|
|
||||||
|
# 1. Take the list and parse it from string
|
||||||
|
# 2. Take all the items and join them
|
||||||
|
# 3. Parse them back as string and return
|
||||||
|
values = ",".join(splitvalues[0:-1])
|
||||||
|
print(f"VALUES: {values}")
|
||||||
|
tmp = json.loads(values)
|
||||||
|
print(f"TMP: {tmp}")
|
||||||
|
#tmp = tmp[1:-1]
|
||||||
|
#print(f"TMP2: {tmp}")
|
||||||
|
try:
|
||||||
|
newvalues = splitvalues[-1].join(str(item).strip() for item in tmp)
|
||||||
|
except TypeError:
|
||||||
|
newvalues = splitvalues[-1].join(json.dumps(item).strip() for item in tmp)
|
||||||
|
|
||||||
|
print(f"new: {newvalues}")
|
||||||
|
return newvalues
|
||||||
|
else:
|
||||||
|
print("Returning default")
|
||||||
|
return f"join({data})"
|
||||||
|
|
||||||
|
except (KeyError, IndexError) as e:
|
||||||
|
print(f"ERROR in join(): {e}")
|
||||||
|
except json.decoder.JSONDecodeError as e:
|
||||||
|
print(f"JSON ERROR in join(): {e}")
|
||||||
|
|
||||||
if "len" in thistype or "length" in thistype or "lenght" in thistype:
|
if "len" in thistype or "length" in thistype or "lenght" in thistype:
|
||||||
tmp = ""
|
tmp = ""
|
||||||
try:
|
try:
|
||||||
@@ -919,9 +962,9 @@ class AppBase:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if isinstance(tmp, list):
|
if isinstance(tmp, list):
|
||||||
return len(tmp)
|
return str(len(tmp))
|
||||||
elif isinstance(tmp, object):
|
elif isinstance(tmp, object):
|
||||||
return len(tmp)
|
return str(len(tmp))
|
||||||
|
|
||||||
return str(len(data))
|
return str(len(data))
|
||||||
if "parse" in thistype:
|
if "parse" in thistype:
|
||||||
@@ -967,7 +1010,7 @@ class AppBase:
|
|||||||
#print("Running %s" % data)
|
#print("Running %s" % data)
|
||||||
|
|
||||||
# Look for the INNER wrapper first, then move out
|
# Look for the INNER wrapper first, then move out
|
||||||
wrappers = ["int", "number", "lower", "upper", "trim", "strip", "split", "parse", "len", "length", "lenght"]
|
wrappers = ["int", "number", "lower", "upper", "trim", "strip", "split", "parse", "len", "length", "lenght", "join"]
|
||||||
found = False
|
found = False
|
||||||
for wrapper in wrappers:
|
for wrapper in wrappers:
|
||||||
if wrapper not in data.lower():
|
if wrapper not in data.lower():
|
||||||
@@ -982,8 +1025,8 @@ class AppBase:
|
|||||||
# Do stuff here.
|
# Do stuff here.
|
||||||
innervalue = parse_nested_param(data, maxDepth(data)-0)
|
innervalue = parse_nested_param(data, maxDepth(data)-0)
|
||||||
outervalue = parse_nested_param(data, maxDepth(data)-1)
|
outervalue = parse_nested_param(data, maxDepth(data)-1)
|
||||||
#print("INNER: ", innervalue)
|
print("INNER: ", innervalue)
|
||||||
#print("OUTER: ", outervalue)
|
print("OUTER: ", outervalue)
|
||||||
|
|
||||||
if outervalue != innervalue:
|
if outervalue != innervalue:
|
||||||
#print("Outer: ", outervalue, " inner: ", innervalue)
|
#print("Outer: ", outervalue, " inner: ", innervalue)
|
||||||
@@ -1224,10 +1267,10 @@ class AppBase:
|
|||||||
baseresult = variable["value"]
|
baseresult = variable["value"]
|
||||||
break
|
break
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print("KeyError wf variables: %s" % e)
|
print("[INFO] KeyError wf variables: %s" % e)
|
||||||
pass
|
pass
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
print("TypeError wf variables: %s" % e)
|
print("[INFO] TypeError wf variables: %s" % e)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
print("BEFORE EXECUTION VAR")
|
print("BEFORE EXECUTION VAR")
|
||||||
@@ -1240,10 +1283,10 @@ class AppBase:
|
|||||||
baseresult = variable["value"]
|
baseresult = variable["value"]
|
||||||
break
|
break
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print("KeyError exec variables: %s" % e)
|
print("[INFO] KeyError exec variables: %s" % e)
|
||||||
pass
|
pass
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
print("TypeError exec variables: %s" % e)
|
print("[INFO] TypeError exec variables: %s" % e)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except KeyError as error:
|
except KeyError as error:
|
||||||
@@ -1701,7 +1744,8 @@ class AppBase:
|
|||||||
# Custom format for ${name[0,1,2,...]}$
|
# Custom format for ${name[0,1,2,...]}$
|
||||||
#submatch = "([${]{2}([0-9a-zA-Z_-]+)(\[.*\])[}$]{2})"
|
#submatch = "([${]{2}([0-9a-zA-Z_-]+)(\[.*\])[}$]{2})"
|
||||||
print(f"Returnedvalue: {value}")
|
print(f"Returnedvalue: {value}")
|
||||||
#submatch = "([${]{2}#?([0-9a-zA-Z_-]+)#?(\[.*\])[}$]{2})"
|
# OLD: Used until 13.03.2021: submatch = "([${]{2}#?([0-9a-zA-Z_-]+)#?(\[.*\])[}$]{2})"
|
||||||
|
# \${[0-9a-zA-Z_-]+#?(\[.*?]}\$)
|
||||||
submatch = "([${]{2}#?([0-9a-zA-Z_-]+)#?(\[.*?]}\$))"
|
submatch = "([${]{2}#?([0-9a-zA-Z_-]+)#?(\[.*?]}\$))"
|
||||||
actualitem = re.findall(submatch, value, re.MULTILINE)
|
actualitem = re.findall(submatch, value, re.MULTILINE)
|
||||||
try:
|
try:
|
||||||
@@ -1722,18 +1766,24 @@ class AppBase:
|
|||||||
# Loop WITH variables go in else.
|
# Loop WITH variables go in else.
|
||||||
print("Before first part in multiexec!")
|
print("Before first part in multiexec!")
|
||||||
handled = False
|
handled = False
|
||||||
|
|
||||||
|
# Has a loop without a variable used inside
|
||||||
if len(actualitem[0]) > 2 and actualitem[0][1] == "SHUFFLE_NO_SPLITTER":
|
if len(actualitem[0]) > 2 and actualitem[0][1] == "SHUFFLE_NO_SPLITTER":
|
||||||
|
|
||||||
print("(1) Pre replacement: %s" % actualitem[0][2])
|
print("(1) Pre replacement: %s" % actualitem[0][2])
|
||||||
tmpitem = value
|
tmpitem = value
|
||||||
|
|
||||||
replacement = actualitem[0][2]
|
index = 0
|
||||||
|
replacement = actualitem[index][2]
|
||||||
|
if replacement.endswith("}$"):
|
||||||
|
replacement = replacement[:-2]
|
||||||
|
|
||||||
if replacement.startswith("\"") and replacement.endswith("\""):
|
if replacement.startswith("\"") and replacement.endswith("\""):
|
||||||
replacement = replacement[1:len(replacement)-1]
|
replacement = replacement[1:len(replacement)-1]
|
||||||
|
|
||||||
print("POST replacement: %s" % replacement)
|
print("POST replacement: %s" % replacement)
|
||||||
|
|
||||||
#json_replacement = tmpitem.replace(actualitem[0][0], replacement, 1)
|
#json_replacement = tmpitem.replace(actualitem[index][0], replacement, 1)
|
||||||
#print("AFTER POST replacement: %s" % json_replacement)
|
#print("AFTER POST replacement: %s" % json_replacement)
|
||||||
#json_replacement = replacement
|
#json_replacement = replacement
|
||||||
try:
|
try:
|
||||||
@@ -1755,9 +1805,9 @@ class AppBase:
|
|||||||
for i in range(len(json_replacement)):
|
for i in range(len(json_replacement)):
|
||||||
if isinstance(json_replacement[i], dict) or isinstance(json_replacement[i], list):
|
if isinstance(json_replacement[i], dict) or isinstance(json_replacement[i], list):
|
||||||
tmp_replacer = json.dumps(json_replacement[i])
|
tmp_replacer = json.dumps(json_replacement[i])
|
||||||
newvalue = tmpitem.replace(actualitem[0][0], tmp_replacer, 1)
|
newvalue = tmpitem.replace(actualitem[index][0], tmp_replacer, 1)
|
||||||
else:
|
else:
|
||||||
newvalue = tmpitem.replace(actualitem[0][0], json_replacement[i], 1)
|
newvalue = tmpitem.replace(actualitem[index][0], json_replacement[i], 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
newvalue = json.loads(newvalue)
|
newvalue = json.loads(newvalue)
|
||||||
@@ -1770,7 +1820,7 @@ class AppBase:
|
|||||||
print("New replacement: %s" % new_replacement)
|
print("New replacement: %s" % new_replacement)
|
||||||
|
|
||||||
# New
|
# New
|
||||||
tmpitem = tmpitem.replace(actualitem[0][0], replacement, 1)
|
tmpitem = tmpitem.replace(actualitem[index][0], replacement, 1)
|
||||||
|
|
||||||
# This code handles files.
|
# This code handles files.
|
||||||
resultarray = []
|
resultarray = []
|
||||||
@@ -1821,9 +1871,15 @@ class AppBase:
|
|||||||
try:
|
try:
|
||||||
to_be_replaced = replace[0]
|
to_be_replaced = replace[0]
|
||||||
actualitem = replace[2]
|
actualitem = replace[2]
|
||||||
|
if actualitem.endswith("}$"):
|
||||||
|
actualitem = actualitem[:-2]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
#print(f"\n\nTMPITEM: {actualitem}\n\n")
|
||||||
|
#actualitem = parse_wrapper_start(actualitem)
|
||||||
|
#print(f"\n\nTMPITEM2: {actualitem}\n\n")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
itemlist = json.loads(actualitem)
|
itemlist = json.loads(actualitem)
|
||||||
if len(itemlist) > minlength:
|
if len(itemlist) > minlength:
|
||||||
@@ -1837,6 +1893,10 @@ class AppBase:
|
|||||||
|
|
||||||
replacements[to_be_replaced] = actualitem
|
replacements[to_be_replaced] = actualitem
|
||||||
|
|
||||||
|
|
||||||
|
# Parses the data as string with length, split etc. before moving on.
|
||||||
|
|
||||||
|
|
||||||
#print("In second part of else: %s" % (len(itemlist)))
|
#print("In second part of else: %s" % (len(itemlist)))
|
||||||
# This is a result array for JUST this value..
|
# This is a result array for JUST this value..
|
||||||
# What if there are more?
|
# What if there are more?
|
||||||
|
|||||||
+11
-547
@@ -42,7 +42,6 @@ import (
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
"github.com/google/go-github/v28/github"
|
"github.com/google/go-github/v28/github"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
|
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
"github.com/go-git/go-billy/v5/memfs"
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
@@ -671,7 +670,7 @@ func handleApiAuthentication(resp http.ResponseWriter, request *http.Request) (U
|
|||||||
// Should basically never happen
|
// Should basically never happen
|
||||||
Userdata, err := getUser(ctx, session.Id)
|
Userdata, err := getUser(ctx, session.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Username %s doesn't exist (authcheck): %s", session.Username, err)
|
log.Printf("[INFO] Username %s doesn't exist (authcheck): %s", session.Username, err)
|
||||||
return User{}, err
|
return User{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1770,90 +1769,6 @@ type passwordChange struct {
|
|||||||
Currentpassword string `json:"currentpassword"`
|
Currentpassword string `json:"currentpassword"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePasswordResetMail(resp http.ResponseWriter, request *http.Request) {
|
|
||||||
cors := handleCors(resp, request)
|
|
||||||
if cors {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Handling password reset mail")
|
|
||||||
defaultMessage := "We have sent you an email :)"
|
|
||||||
|
|
||||||
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": "%s"}`, defaultMessage)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type passwordReset struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var t passwordReset
|
|
||||||
err = json.Unmarshal(body, &t)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed unmarshaling: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, defaultMessage)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
Userdata, err := getUser(ctx, t.Username)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (pw reset mail): %s", t.Username, err)
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resetToken := uuid.NewV4()
|
|
||||||
// FIXME:
|
|
||||||
// Weakness with this system is that you can spam someone with password resets,
|
|
||||||
// and they would never be able to reset, as a new token is always generated
|
|
||||||
url := fmt.Sprintf("https://shuffler.io/passwordreset/%s", resetToken.String())
|
|
||||||
|
|
||||||
Userdata.ResetReference = resetToken.String()
|
|
||||||
Userdata.ResetTimeout = 0
|
|
||||||
err = setUser(ctx, Userdata)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error patching User for mail %s: %s", Userdata.Username, err)
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("%#v", Userdata)
|
|
||||||
addr := t.Username
|
|
||||||
const confirmMessage = `
|
|
||||||
Reset URL :)
|
|
||||||
|
|
||||||
%s
|
|
||||||
`
|
|
||||||
|
|
||||||
msg := &mail.Message{
|
|
||||||
Sender: "Shuffle <frikky@shuffler.io>",
|
|
||||||
To: []string{addr},
|
|
||||||
Subject: "Reset your password - Shuffle",
|
|
||||||
Body: fmt.Sprintf(confirmMessage, url),
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(msg.Body)
|
|
||||||
if err := mail.Send(ctx, msg); err != nil {
|
|
||||||
log.Printf("Couldn't send email: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
// Generate an email to send
|
|
||||||
// Generate a reset code with a reset link
|
|
||||||
// Build frontend to handle reset link with "new password" etc.
|
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "%s"}`, defaultMessage)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePasswordReset(resp http.ResponseWriter, request *http.Request) {
|
func handlePasswordReset(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -4954,398 +4869,6 @@ func getDocs(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write(b)
|
resp.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutlookProfile struct {
|
|
||||||
OdataContext string `json:"@odata.context"`
|
|
||||||
BusinessPhones []string `json:"businessPhones"`
|
|
||||||
DisplayName string `json:"displayName"`
|
|
||||||
GivenName string `json:"givenName"`
|
|
||||||
JobTitle interface{} `json:"jobTitle"`
|
|
||||||
Mail string `json:"mail"`
|
|
||||||
MobilePhone interface{} `json:"mobilePhone"`
|
|
||||||
OfficeLocation interface{} `json:"officeLocation"`
|
|
||||||
PreferredLanguage interface{} `json:"preferredLanguage"`
|
|
||||||
Surname string `json:"surname"`
|
|
||||||
UserPrincipalName string `json:"userPrincipalName"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutlookFolder struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
DisplayName string `json:"displayName"`
|
|
||||||
ParentFolderID string `json:"parentFolderId"`
|
|
||||||
ChildFolderCount int `json:"childFolderCount"`
|
|
||||||
UnreadItemCount int `json:"unreadItemCount"`
|
|
||||||
TotalItemCount int `json:"totalItemCount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutlookFolders struct {
|
|
||||||
OdataContext string `json:"@odata.context"`
|
|
||||||
OdataNextLink string `json:"@odata.nextLink"`
|
|
||||||
Value []OutlookFolder `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOutlookFolders(client *http.Client) (OutlookFolders, error) {
|
|
||||||
requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/frikky@shuffletest.onmicrosoft.com/mailfolders")
|
|
||||||
|
|
||||||
ret, err := client.Get(requestUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("FolderErr: %s", err)
|
|
||||||
return OutlookFolders{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if ret.StatusCode != 200 {
|
|
||||||
log.Printf("Status folders: %d", ret.StatusCode)
|
|
||||||
return OutlookFolders{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(ret.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Body: %s", err)
|
|
||||||
return OutlookFolders{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("Body: %s", string(body))
|
|
||||||
|
|
||||||
mailfolders := OutlookFolders{}
|
|
||||||
err = json.Unmarshal(body, &mailfolders)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unmarshal: %s", err)
|
|
||||||
return OutlookFolders{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Printf("%#v", mailfolders)
|
|
||||||
// FIXME - recursion for subfolders
|
|
||||||
// Recursive struct
|
|
||||||
// folderEndpoint := fmt.Sprintf("%s/%s/childfolders?$top=40", requestUrl, parentId)
|
|
||||||
//for _, folder := range mailfolders.Value {
|
|
||||||
// log.Println(folder.DisplayName)
|
|
||||||
//}
|
|
||||||
|
|
||||||
return mailfolders, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOutlookProfile(client *http.Client) (OutlookProfile, error) {
|
|
||||||
requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/me?$select=mail")
|
|
||||||
|
|
||||||
ret, err := client.Get(requestUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("FolderErr: %s", err)
|
|
||||||
return OutlookProfile{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Status folders: %d", ret.StatusCode)
|
|
||||||
body, err := ioutil.ReadAll(ret.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Body: %s", err)
|
|
||||||
return OutlookProfile{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
profile := OutlookProfile{}
|
|
||||||
err = json.Unmarshal(body, &profile)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Unmarshal: %s", err)
|
|
||||||
return OutlookProfile{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return profile, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleNewOutlookRegister(resp http.ResponseWriter, request *http.Request) {
|
|
||||||
code := request.URL.Query().Get("code")
|
|
||||||
if len(code) == 0 {
|
|
||||||
log.Println("No code")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s%s", request.Host, request.URL.EscapedPath())
|
|
||||||
log.Println(url)
|
|
||||||
ctx := context.Background()
|
|
||||||
client, accessToken, err := getOutlookClient(ctx, code, OauthToken{}, url)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Oauth client failure - outlook register: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// This should be possible, and will also give the actual username
|
|
||||||
profile, err := getOutlookProfile(client)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Outlook profile failure: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a state workaround, which should really be for CSRF checks lol
|
|
||||||
state := request.URL.Query().Get("state")
|
|
||||||
if len(state) == 0 {
|
|
||||||
log.Println("No state")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stateitems := strings.Split(state, "%26")
|
|
||||||
if len(stateitems) == 1 {
|
|
||||||
stateitems = strings.Split(state, "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME - trigger auth
|
|
||||||
senderUser := ""
|
|
||||||
trigger := TriggerAuth{}
|
|
||||||
for _, item := range stateitems {
|
|
||||||
itemsplit := strings.Split(item, "%3D")
|
|
||||||
if len(itemsplit) == 1 {
|
|
||||||
itemsplit = strings.Split(item, "=")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(itemsplit) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do something here
|
|
||||||
if itemsplit[0] == "workflow_id" {
|
|
||||||
trigger.WorkflowId = itemsplit[1]
|
|
||||||
} else if itemsplit[0] == "trigger_id" {
|
|
||||||
trigger.Id = itemsplit[1]
|
|
||||||
} else if itemsplit[0] == "type" {
|
|
||||||
trigger.Type = itemsplit[1]
|
|
||||||
} else if itemsplit[0] == "username" {
|
|
||||||
trigger.Username = itemsplit[1]
|
|
||||||
trigger.Owner = itemsplit[1]
|
|
||||||
senderUser = itemsplit[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// THis is an override based on the user in oauth return
|
|
||||||
trigger.Username = profile.Mail
|
|
||||||
trigger.Code = code
|
|
||||||
trigger.OauthToken = OauthToken{
|
|
||||||
AccessToken: accessToken.AccessToken,
|
|
||||||
TokenType: accessToken.TokenType,
|
|
||||||
RefreshToken: accessToken.RefreshToken,
|
|
||||||
Expiry: accessToken.Expiry,
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("%#v", trigger)
|
|
||||||
if trigger.WorkflowId == "" || trigger.Id == "" || trigger.Username == "" || trigger.Type == "" {
|
|
||||||
log.Printf("All oauth items need to contain data to register a new state")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should also update the user
|
|
||||||
Userdata, err := getUser(ctx, senderUser)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (oauth2): %s", trigger.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Userdata.Authentication = append(Userdata.Authentication, UserAuth{
|
|
||||||
Name: "Outlook",
|
|
||||||
Description: "oauth2",
|
|
||||||
Workflows: []string{trigger.WorkflowId},
|
|
||||||
Username: trigger.Username,
|
|
||||||
Fields: []UserAuthField{
|
|
||||||
UserAuthField{
|
|
||||||
Key: "trigger_id",
|
|
||||||
Value: trigger.Id,
|
|
||||||
},
|
|
||||||
UserAuthField{
|
|
||||||
Key: "username",
|
|
||||||
Value: trigger.Username,
|
|
||||||
},
|
|
||||||
UserAuthField{
|
|
||||||
Key: "code",
|
|
||||||
Value: code,
|
|
||||||
},
|
|
||||||
UserAuthField{
|
|
||||||
Key: "type",
|
|
||||||
Value: trigger.Type,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set apikey for the user if they don't have one
|
|
||||||
if len(Userdata.ApiKey) == 0 {
|
|
||||||
newUser, err := generateApikey(ctx, *Userdata)
|
|
||||||
Userdata = &newUser
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to generate apikey for user %s when creating outlook sub: %s", Userdata.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//err = setUser(Userdata)
|
|
||||||
//if err != nil {
|
|
||||||
// log.Printf("Failed setting user data for %s: %s", Userdata.Username, err)
|
|
||||||
// resp.WriteHeader(401)
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
err = setTriggerAuth(ctx, trigger)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to set trigger auth for %s - %s", trigger.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME - not sure if these are good at all :)
|
|
||||||
environmentVariables := map[string]string{
|
|
||||||
"FUNCTION_APIKEY": Userdata.ApiKey,
|
|
||||||
"CALLBACKURL": "https://shuffler.io",
|
|
||||||
"WORKFLOW_ID": trigger.WorkflowId,
|
|
||||||
"TRIGGER_ID": trigger.Id,
|
|
||||||
}
|
|
||||||
|
|
||||||
applocation := fmt.Sprintf("gs://%s/triggers/outlooktrigger.zip", bucketName)
|
|
||||||
hookname := fmt.Sprintf("outlooktrigger_%s", trigger.Id)
|
|
||||||
|
|
||||||
err = deployCloudFunctionGo(ctx, hookname, defaultLocation, applocation, environmentVariables)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error deploying hook: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Issue with starting hook. Please wait a second and try again"}`)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write([]byte(`{"success": true}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
type OauthToken struct {
|
|
||||||
AccessToken string `json:"AccessToken" datastore:"AccessToken,noindex"`
|
|
||||||
TokenType string `json:"TokenType" datastore:"TokenType,noindex"`
|
|
||||||
RefreshToken string `json:"RefreshToken" datastore:"RefreshToken,noindex"`
|
|
||||||
Expiry time.Time `json:"Expiry" datastore:"Expiry,noindex"`
|
|
||||||
}
|
|
||||||
type TriggerAuth struct {
|
|
||||||
Id string `json:"id" datastore:"id"`
|
|
||||||
SubscriptionId string `json:"subscriptionId" datastore:"subscriptionId"`
|
|
||||||
|
|
||||||
Username string `json:"username" datastore:"username,noindex"`
|
|
||||||
WorkflowId string `json:"workflow_id" datastore:"workflow_id,noindex"`
|
|
||||||
Owner string `json:"owner" datastore:"owner"`
|
|
||||||
Type string `json:"type" datastore:"type"`
|
|
||||||
Code string `json:"code,omitempty" datastore:"code,noindex"`
|
|
||||||
OauthToken OauthToken `json:"oauth_token,omitempty" datastore:"oauth_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTriggerAuth(ctx context.Context, id string) (*TriggerAuth, error) {
|
|
||||||
key := datastore.NameKey("trigger_auth", strings.ToLower(id), nil)
|
|
||||||
triggerauth := &TriggerAuth{}
|
|
||||||
if err := dbclient.Get(ctx, key, triggerauth); err != nil {
|
|
||||||
return &TriggerAuth{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return triggerauth, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTriggerAuth(ctx context.Context, trigger TriggerAuth) error {
|
|
||||||
key1 := datastore.NameKey("trigger_auth", strings.ToLower(trigger.Id), nil)
|
|
||||||
|
|
||||||
// New struct, to not add body, author etc
|
|
||||||
if _, err := dbclient.Put(ctx, key1, &trigger); err != nil {
|
|
||||||
log.Printf("Error adding trigger auth: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// THis all of a sudden became really horrible.. fml
|
|
||||||
func getOutlookClient(ctx context.Context, code string, accessToken OauthToken, redirectUri string) (*http.Client, *oauth2.Token, error) {
|
|
||||||
|
|
||||||
conf := &oauth2.Config{
|
|
||||||
ClientID: "",
|
|
||||||
ClientSecret: "",
|
|
||||||
Scopes: []string{
|
|
||||||
"Mail.Read",
|
|
||||||
"User.Read",
|
|
||||||
},
|
|
||||||
RedirectURL: redirectUri,
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: "https://login.microsoftonline.com/common/oauth2/authorize",
|
|
||||||
TokenURL: "https://login.microsoftonline.com/common/oauth2/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(code) > 0 {
|
|
||||||
access_token, err := conf.Exchange(ctx, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Access_token issue: %s", err)
|
|
||||||
return &http.Client{}, access_token, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client := conf.Client(ctx, access_token)
|
|
||||||
return client, access_token, nil
|
|
||||||
} else {
|
|
||||||
// Manually recreate the oauthtoken
|
|
||||||
access_token := &oauth2.Token{
|
|
||||||
AccessToken: accessToken.AccessToken,
|
|
||||||
TokenType: accessToken.TokenType,
|
|
||||||
RefreshToken: accessToken.RefreshToken,
|
|
||||||
Expiry: accessToken.Expiry,
|
|
||||||
}
|
|
||||||
|
|
||||||
client := conf.Client(ctx, access_token)
|
|
||||||
return client, access_token, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleGetOutlookFolders(resp http.ResponseWriter, request *http.Request) {
|
|
||||||
cors := handleCors(resp, request)
|
|
||||||
if cors {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange every time hmm
|
|
||||||
// FIXME
|
|
||||||
// Should really just get the code from the trigger that's being used OR the user
|
|
||||||
triggerId := request.URL.Query().Get("trigger_id")
|
|
||||||
if len(triggerId) == 0 {
|
|
||||||
log.Println("No trigger_id supplied")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
trigger, err := getTriggerAuth(ctx, triggerId)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Trigger %s doesn't exist - outlook folders.", triggerId)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Trigger doesn't exist."}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME - should be shuffler in literally every case except testing lol
|
|
||||||
redirectDomain := "shuffler.io"
|
|
||||||
url := fmt.Sprintf("https://%s/functions/outlook/register", redirectDomain)
|
|
||||||
outlookClient, _, err := getOutlookClient(ctx, "", trigger.OauthToken, url)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Oauth client failure - outlook folders: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
folders, err := getOutlookFolders(outlookClient)
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(folders.Value)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to marshal folderdata")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleGetSpecificStats(resp http.ResponseWriter, request *http.Request) {
|
func handleGetSpecificStats(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -5395,66 +4918,6 @@ func handleGetSpecificStats(resp http.ResponseWriter, request *http.Request) {
|
|||||||
resp.Write([]byte(b))
|
resp.Write([]byte(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGetSpecificTrigger(resp http.ResponseWriter, request *http.Request) {
|
|
||||||
cors := handleCors(resp, request)
|
|
||||||
if cors {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := handleApiAuthentication(resp, request)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Api authentication failed in getting specific workflow: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
location := strings.Split(request.URL.String(), "/")
|
|
||||||
|
|
||||||
var workflowId string
|
|
||||||
if location[1] == "api" {
|
|
||||||
if len(location) <= 4 {
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workflowId = location[4]
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(workflowId, "?") {
|
|
||||||
workflowId = strings.Split(workflowId, "?")[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
trigger, err := getTriggerAuth(ctx, workflowId)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Trigger %s doesn't exist - specific trigger.", workflowId)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.Username != trigger.Owner && user.Role != "admin" {
|
|
||||||
log.Printf("Wrong user (%s) for trigger %s", user.Username, trigger.Id)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger.OauthToken = OauthToken{}
|
|
||||||
trigger.Code = ""
|
|
||||||
|
|
||||||
b, err := json.Marshal(trigger)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to marshal data")
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
|
||||||
resp.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleDeleteOutlookSub(resp http.ResponseWriter, request *http.Request) {
|
func handleDeleteOutlookSub(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
@@ -7545,7 +7008,7 @@ func runInit(ctx context.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed loading repo %s into memory: %s", apis, err)
|
log.Printf("Failed loading repo %s into memory: %s", apis, err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Finished git clone. Looking for updates to the repo.")
|
log.Printf("[INFO] Finished git clone. Looking for updates to the repo.")
|
||||||
dir, err := fs.ReadDir("")
|
dir, err := fs.ReadDir("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed reading folder: %s", err)
|
log.Printf("Failed reading folder: %s", err)
|
||||||
@@ -7856,7 +7319,7 @@ func handleKeyValueCheck(resp http.ResponseWriter, request *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Looking for value %s", value)
|
log.Printf("[INFO] Looking for value %s in Workflow %s of ORG %s", value, workflowExecution.Workflow.ID, org.Id)
|
||||||
|
|
||||||
q := datastore.NewQuery(dbKey).Filter("org_id =", org.Id).Filter("workflow_id =", workflowExecution.Workflow.ID).Filter("parameter_name =", parameterNames).Filter("value =", value)
|
q := datastore.NewQuery(dbKey).Filter("org_id =", org.Id).Filter("workflow_id =", workflowExecution.Workflow.ID).Filter("parameter_name =", parameterNames).Filter("value =", value)
|
||||||
foundCount, err := dbclient.Count(ctx, q)
|
foundCount, err := dbclient.Count(ctx, q)
|
||||||
@@ -7875,7 +7338,7 @@ func handleKeyValueCheck(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[INFO] Should validate if value %s in app %s exists WITH ORG %s", workflowExecution.Workflow.ID)
|
//log.Printf("[INFO] Should validate if value %s in app %s exists WITH ORG %s", workflowExecution.Workflow.ID)
|
||||||
|
|
||||||
for _, value := range value.ParameterValues {
|
for _, value := range value.ParameterValues {
|
||||||
if len(value) == 0 {
|
if len(value) == 0 {
|
||||||
@@ -7883,7 +7346,7 @@ func handleKeyValueCheck(resp http.ResponseWriter, request *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] Looking for value %s", value)
|
log.Printf("[INFO] Looking for value %s in ORG %s", value, org.Id)
|
||||||
|
|
||||||
q := datastore.NewQuery(dbKey).Filter("org_id =", org.Id).Filter("workflow_id =", "").Filter("parameter_name =", parameterNames).Filter("value =", value)
|
q := datastore.NewQuery(dbKey).Filter("org_id =", org.Id).Filter("workflow_id =", "").Filter("parameter_name =", parameterNames).Filter("value =", value)
|
||||||
foundCount, err := dbclient.Count(ctx, q)
|
foundCount, err := dbclient.Count(ctx, q)
|
||||||
@@ -8653,11 +8116,6 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/hooks/{key}", handleWebhookCallback).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/hooks/{key}", handleWebhookCallback).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/hooks/{key}/delete", handleDeleteHook).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/hooks/{key}/delete", handleDeleteHook).Methods("DELETE", "OPTIONS")
|
||||||
|
|
||||||
// Trigger hmm
|
|
||||||
//r.HandleFunc("/api/v1/triggers/{key}", handleGetSpecificTrigger).Methods("GET", "OPTIONS")
|
|
||||||
|
|
||||||
r.HandleFunc("/api/v1/stats/{key}", handleGetSpecificStats).Methods("GET", "OPTIONS")
|
|
||||||
|
|
||||||
// OpenAPI configuration
|
// OpenAPI configuration
|
||||||
r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS")
|
r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS")
|
||||||
@@ -8693,6 +8151,12 @@ func initHandlers() {
|
|||||||
r.HandleFunc("/api/v1/files/{fileId}", handleDeleteFile).Methods("DELETE", "OPTIONS")
|
r.HandleFunc("/api/v1/files/{fileId}", handleDeleteFile).Methods("DELETE", "OPTIONS")
|
||||||
r.HandleFunc("/api/v1/files", handleGetFiles).Methods("GET", "OPTIONS")
|
r.HandleFunc("/api/v1/files", handleGetFiles).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
|
// Trigger hmm
|
||||||
|
r.HandleFunc("/api/v1/triggers/outlook/register", handleNewOutlookRegister).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/triggers/outlook/getFolders", handleGetOutlookFolders).Methods("GET", "OPTIONS")
|
||||||
|
r.HandleFunc("/api/v1/triggers/outlook/{key}", handleGetSpecificTrigger).Methods("GET", "OPTIONS")
|
||||||
|
//r.HandleFunc("/api/v1/stats/{key}", handleGetSpecificStats).Methods("GET", "OPTIONS")
|
||||||
|
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,468 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/datastore"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OutlookProfile struct {
|
||||||
|
OdataContext string `json:"@odata.context"`
|
||||||
|
BusinessPhones []string `json:"businessPhones"`
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
GivenName string `json:"givenName"`
|
||||||
|
JobTitle interface{} `json:"jobTitle"`
|
||||||
|
Mail string `json:"mail"`
|
||||||
|
MobilePhone interface{} `json:"mobilePhone"`
|
||||||
|
OfficeLocation interface{} `json:"officeLocation"`
|
||||||
|
PreferredLanguage interface{} `json:"preferredLanguage"`
|
||||||
|
Surname string `json:"surname"`
|
||||||
|
UserPrincipalName string `json:"userPrincipalName"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutlookFolder struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
ParentFolderID string `json:"parentFolderId"`
|
||||||
|
ChildFolderCount int `json:"childFolderCount"`
|
||||||
|
UnreadItemCount int `json:"unreadItemCount"`
|
||||||
|
TotalItemCount int `json:"totalItemCount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutlookFolders struct {
|
||||||
|
OdataContext string `json:"@odata.context"`
|
||||||
|
OdataNextLink string `json:"@odata.nextLink"`
|
||||||
|
Value []OutlookFolder `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOutlookFolders(client *http.Client) (OutlookFolders, error) {
|
||||||
|
requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/ec03b4f2-fccf-4c35-b0eb-be85a0f5dd43/mailFolders")
|
||||||
|
|
||||||
|
ret, err := client.Get(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] FolderErr: %s", err)
|
||||||
|
return OutlookFolders{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(ret.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARNING] Failed body decoding from mailfolders")
|
||||||
|
return OutlookFolders{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Folder Body: %s", string(body))
|
||||||
|
log.Printf("[INFO] Status folders: %d", ret.StatusCode)
|
||||||
|
if ret.StatusCode != 200 {
|
||||||
|
return OutlookFolders{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("Body: %s", string(body))
|
||||||
|
|
||||||
|
mailfolders := OutlookFolders{}
|
||||||
|
err = json.Unmarshal(body, &mailfolders)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unmarshal: %s", err)
|
||||||
|
return OutlookFolders{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("%#v", mailfolders)
|
||||||
|
// FIXME - recursion for subfolders
|
||||||
|
// Recursive struct
|
||||||
|
// folderEndpoint := fmt.Sprintf("%s/%s/childfolders?$top=40", requestUrl, parentId)
|
||||||
|
//for _, folder := range mailfolders.Value {
|
||||||
|
// log.Println(folder.DisplayName)
|
||||||
|
//}
|
||||||
|
|
||||||
|
return mailfolders, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOutlookProfile(client *http.Client) (OutlookProfile, error) {
|
||||||
|
requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/me?$select=mail")
|
||||||
|
|
||||||
|
ret, err := client.Get(requestUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] Folder error: %s", err)
|
||||||
|
return OutlookProfile{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Status profile: %d", ret.StatusCode)
|
||||||
|
body, err := ioutil.ReadAll(ret.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] Body: %s", err)
|
||||||
|
return OutlookProfile{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] BODY: %s", string(body))
|
||||||
|
|
||||||
|
profile := OutlookProfile{}
|
||||||
|
err = json.Unmarshal(body, &profile)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unmarshal: %s", err)
|
||||||
|
return OutlookProfile{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleNewOutlookRegister(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
code := request.URL.Query().Get("code")
|
||||||
|
if len(code) == 0 {
|
||||||
|
log.Println("No code")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("http://%s%s", request.Host, request.URL.EscapedPath())
|
||||||
|
log.Println(url)
|
||||||
|
ctx := context.Background()
|
||||||
|
client, accessToken, err := getOutlookClient(ctx, code, OauthToken{}, url)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Oauth client failure - outlook register: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should be possible, and will also give the actual username
|
||||||
|
profile, err := getOutlookProfile(client)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Outlook profile failure: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a state workaround, which should really be for CSRF checks lol
|
||||||
|
state := request.URL.Query().Get("state")
|
||||||
|
if len(state) == 0 {
|
||||||
|
log.Println("No state")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
stateitems := strings.Split(state, "%26")
|
||||||
|
if len(stateitems) == 1 {
|
||||||
|
stateitems = strings.Split(state, "&")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME - trigger auth
|
||||||
|
senderUser := ""
|
||||||
|
trigger := TriggerAuth{}
|
||||||
|
for _, item := range stateitems {
|
||||||
|
itemsplit := strings.Split(item, "%3D")
|
||||||
|
if len(itemsplit) == 1 {
|
||||||
|
itemsplit = strings.Split(item, "=")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(itemsplit) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do something here
|
||||||
|
if itemsplit[0] == "workflow_id" {
|
||||||
|
trigger.WorkflowId = itemsplit[1]
|
||||||
|
} else if itemsplit[0] == "trigger_id" {
|
||||||
|
trigger.Id = itemsplit[1]
|
||||||
|
} else if itemsplit[0] == "type" {
|
||||||
|
trigger.Type = itemsplit[1]
|
||||||
|
} else if itemsplit[0] == "username" {
|
||||||
|
trigger.Username = itemsplit[1]
|
||||||
|
trigger.Owner = itemsplit[1]
|
||||||
|
senderUser = itemsplit[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// THis is an override based on the user in oauth return
|
||||||
|
trigger.Username = profile.Mail
|
||||||
|
trigger.Code = code
|
||||||
|
trigger.OauthToken = OauthToken{
|
||||||
|
AccessToken: accessToken.AccessToken,
|
||||||
|
TokenType: accessToken.TokenType,
|
||||||
|
RefreshToken: accessToken.RefreshToken,
|
||||||
|
Expiry: accessToken.Expiry,
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("%#v", trigger)
|
||||||
|
log.Println(trigger.WorkflowId)
|
||||||
|
log.Println(trigger.Id)
|
||||||
|
log.Println(trigger.Username)
|
||||||
|
log.Println(trigger.Type)
|
||||||
|
if trigger.WorkflowId == "" || trigger.Id == "" || trigger.Username == "" || trigger.Type == "" {
|
||||||
|
log.Printf("[INFO] All oauth items need to contain data to register a new state")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should also update the user
|
||||||
|
log.Printf("[INFO] Attempting to set up outlook trigger for %s", senderUser)
|
||||||
|
Userdata, err := getUser(ctx, senderUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] Username %s doesn't exist (oauth2): %s", trigger.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Userdata.Authentication = append(Userdata.Authentication, UserAuth{
|
||||||
|
Name: "Outlook",
|
||||||
|
Description: "oauth2",
|
||||||
|
Workflows: []string{trigger.WorkflowId},
|
||||||
|
Username: trigger.Username,
|
||||||
|
Fields: []UserAuthField{
|
||||||
|
UserAuthField{
|
||||||
|
Key: "trigger_id",
|
||||||
|
Value: trigger.Id,
|
||||||
|
},
|
||||||
|
UserAuthField{
|
||||||
|
Key: "username",
|
||||||
|
Value: trigger.Username,
|
||||||
|
},
|
||||||
|
UserAuthField{
|
||||||
|
Key: "code",
|
||||||
|
Value: code,
|
||||||
|
},
|
||||||
|
UserAuthField{
|
||||||
|
Key: "type",
|
||||||
|
Value: trigger.Type,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set apikey for the user if they don't have one
|
||||||
|
err = setUser(ctx, Userdata)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed setting user data for %s: %s", Userdata.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = setTriggerAuth(ctx, trigger)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to set trigger auth for %s - %s", trigger.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write([]byte(`{"success": true}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
type OauthToken struct {
|
||||||
|
AccessToken string `json:"AccessToken" datastore:"AccessToken,noindex"`
|
||||||
|
TokenType string `json:"TokenType" datastore:"TokenType,noindex"`
|
||||||
|
RefreshToken string `json:"RefreshToken" datastore:"RefreshToken,noindex"`
|
||||||
|
Expiry time.Time `json:"Expiry" datastore:"Expiry,noindex"`
|
||||||
|
}
|
||||||
|
type TriggerAuth struct {
|
||||||
|
Id string `json:"id" datastore:"id"`
|
||||||
|
SubscriptionId string `json:"subscriptionId" datastore:"subscriptionId"`
|
||||||
|
|
||||||
|
Username string `json:"username" datastore:"username,noindex"`
|
||||||
|
WorkflowId string `json:"workflow_id" datastore:"workflow_id,noindex"`
|
||||||
|
Owner string `json:"owner" datastore:"owner"`
|
||||||
|
Type string `json:"type" datastore:"type"`
|
||||||
|
Code string `json:"code,omitempty" datastore:"code,noindex"`
|
||||||
|
OauthToken OauthToken `json:"oauth_token,omitempty" datastore:"oauth_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTriggerAuth(ctx context.Context, id string) (*TriggerAuth, error) {
|
||||||
|
key := datastore.NameKey("trigger_auth", strings.ToLower(id), nil)
|
||||||
|
triggerauth := &TriggerAuth{}
|
||||||
|
if err := dbclient.Get(ctx, key, triggerauth); err != nil {
|
||||||
|
return &TriggerAuth{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return triggerauth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTriggerAuth(ctx context.Context, trigger TriggerAuth) error {
|
||||||
|
key1 := datastore.NameKey("trigger_auth", strings.ToLower(trigger.Id), nil)
|
||||||
|
|
||||||
|
// New struct, to not add body, author etc
|
||||||
|
if _, err := dbclient.Put(ctx, key1, &trigger); err != nil {
|
||||||
|
log.Printf("Error adding trigger auth: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// THis all of a sudden became really horrible.. fml
|
||||||
|
func getOutlookClient(ctx context.Context, code string, accessToken OauthToken, redirectUri string) (*http.Client, *oauth2.Token, error) {
|
||||||
|
|
||||||
|
conf := &oauth2.Config{
|
||||||
|
ClientID: "fd55c175-aa30-4fa6-b303-09a29fb3f750",
|
||||||
|
ClientSecret: "14OBKgUpov.D7fe0~hp0z-cIQdP~SlYm.8",
|
||||||
|
Scopes: []string{
|
||||||
|
"Mail.Read",
|
||||||
|
},
|
||||||
|
RedirectURL: redirectUri,
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: "https://login.microsoftonline.com/common/oauth2/authorize",
|
||||||
|
TokenURL: "https://login.microsoftonline.com/common/oauth2/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(code) > 0 {
|
||||||
|
access_token, err := conf.Exchange(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Access_token issue: %s", err)
|
||||||
|
return &http.Client{}, access_token, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := conf.Client(ctx, access_token)
|
||||||
|
return client, access_token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually recreate the oauthtoken
|
||||||
|
access_token := &oauth2.Token{
|
||||||
|
AccessToken: accessToken.AccessToken,
|
||||||
|
TokenType: accessToken.TokenType,
|
||||||
|
RefreshToken: accessToken.RefreshToken,
|
||||||
|
Expiry: accessToken.Expiry,
|
||||||
|
}
|
||||||
|
|
||||||
|
client := conf.Client(ctx, access_token)
|
||||||
|
return client, access_token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetOutlookFolders(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
cors := handleCors(resp, request)
|
||||||
|
if cors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange every time hmm
|
||||||
|
// FIXME
|
||||||
|
// Should really just get the code from the trigger that's being used OR the user
|
||||||
|
triggerId := request.URL.Query().Get("trigger_id")
|
||||||
|
if len(triggerId) == 0 {
|
||||||
|
log.Println("No trigger_id supplied")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
trigger, err := getTriggerAuth(ctx, triggerId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] Trigger %s doesn't exist - outlook folders.", triggerId)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Trigger doesn't exist."}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//client, accessToken, err := getOutlookClient(ctx, code, OauthToken{}, url)
|
||||||
|
//if err != nil {
|
||||||
|
// log.Printf("Oauth client failure - outlook register: %s", err)
|
||||||
|
// resp.WriteHeader(401)
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
// FIXME - should be shuffler in literally every case except testing lol
|
||||||
|
//log.Printf("TRIGGER: %#v", trigger)
|
||||||
|
redirectDomain := "localhost:5001"
|
||||||
|
url := fmt.Sprintf("http://%s/api/v1/triggers/outlook/register", redirectDomain)
|
||||||
|
outlookClient, _, err := getOutlookClient(ctx, "", trigger.OauthToken, url)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARNING] Oauth client failure - outlook folders: %s", err)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed creating outlook client"}`))
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should be possible, and will also give the actual username
|
||||||
|
/*
|
||||||
|
profile, err := getOutlookProfile(outlookClient)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Outlook profile failure: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("PROFILE: %#v", profile)
|
||||||
|
*/
|
||||||
|
|
||||||
|
folders, err := getOutlookFolders(outlookClient)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARNING] Failed setting outlook folders: %s", err)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed getting outlook folders"}`))
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(folders.Value)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[INFO] Failed to marshal folderdata")
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Failed decoding JSON"}`))
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleGetSpecificTrigger(resp http.ResponseWriter, request *http.Request) {
|
||||||
|
cors := handleCors(resp, request)
|
||||||
|
if cors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in getting specific workflow: %s", err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
location := strings.Split(request.URL.String(), "/")
|
||||||
|
|
||||||
|
var workflowId string
|
||||||
|
if location[1] == "api" {
|
||||||
|
if len(location) <= 4 {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
workflowId = location[5]
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(workflowId, "?") {
|
||||||
|
workflowId = strings.Split(workflowId, "?")[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
trigger, err := getTriggerAuth(ctx, workflowId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[INFO] Trigger %s doesn't exist - specific trigger.", workflowId)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": ""}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Username != trigger.Owner && user.Role != "admin" {
|
||||||
|
log.Printf("Wrong user (%s) for trigger %s", user.Username, trigger.Id)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.OauthToken = OauthToken{}
|
||||||
|
trigger.Code = ""
|
||||||
|
|
||||||
|
b, err := json.Marshal(trigger)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to marshal data")
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteHeader(200)
|
||||||
|
resp.Write(b)
|
||||||
|
}
|
||||||
@@ -982,7 +982,7 @@ func validateNewWorkerExecution(body []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if execution.Status == "EXECUTING" {
|
if execution.Status == "EXECUTING" {
|
||||||
log.Printf("[INFO] Inside executing.")
|
//log.Printf("[INFO] Inside executing.")
|
||||||
extra := 0
|
extra := 0
|
||||||
for _, trigger := range execution.Workflow.Triggers {
|
for _, trigger := range execution.Workflow.Triggers {
|
||||||
//log.Printf("Appname trigger (0): %s", trigger.AppName)
|
//log.Printf("Appname trigger (0): %s", trigger.AppName)
|
||||||
@@ -3992,7 +3992,7 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
workflow, err := getWorkflow(ctx, fileId)
|
workflow, err := getWorkflow(ctx, fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed getting the workflow locally (stop schedule): %s", err)
|
log.Printf("[WARNING] Failed getting the workflow locally (stop schedule): %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4001,7 +4001,7 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// FIXME - have a check for org etc too..
|
// FIXME - have a check for org etc too..
|
||||||
// FIXME - admin check like this? idk
|
// FIXME - admin check like this? idk
|
||||||
if user.Id != workflow.Owner && user.Role != "admin" && user.Role != "scheduler" {
|
if user.Id != workflow.Owner && user.Role != "admin" && user.Role != "scheduler" {
|
||||||
log.Printf("Wrong user (%s) for workflow %s (stop schedule)", user.Username, workflow.ID)
|
log.Printf("[WARNING] Wrong user (%s) for workflow %s (stop schedule)", user.Username, workflow.ID)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4009,7 +4009,7 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
schedule, err := getSchedule(ctx, scheduleId)
|
schedule, err := getSchedule(ctx, scheduleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed finding schedule %s", scheduleId)
|
log.Printf("[WARNING] Failed finding schedule %s", scheduleId)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4039,15 +4039,15 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
err = executeCloudAction(action, org.SyncConfig.Apikey)
|
err = executeCloudAction(action, org.SyncConfig.Apikey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed cloud action STOP schedule: %s", err)
|
log.Printf("[WARNING] Failed cloud action STOP schedule: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Successfully ran cloud action STOP schedule")
|
log.Printf("[INFO] Successfully ran cloud action STOP schedule")
|
||||||
err = DeleteKey(ctx, "schedules", scheduleId)
|
err = DeleteKey(ctx, "schedules", scheduleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed deleting cloud schedule onprem..")
|
log.Printf("[WARNING] Failed deleting cloud schedule onprem..")
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed deleting cloud schedule"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed deleting cloud schedule"}`)))
|
||||||
return
|
return
|
||||||
@@ -4061,7 +4061,7 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
err = deleteSchedule(ctx, scheduleId)
|
err = deleteSchedule(ctx, scheduleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed deleting schedule: %s", err)
|
log.Printf("[WARNING] Failed deleting schedule: %s", err)
|
||||||
if strings.Contains(err.Error(), "Job not found") {
|
if strings.Contains(err.Error(), "Job not found") {
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
|
||||||
|
|||||||
@@ -2307,10 +2307,12 @@ const AngularWorkflow = (props) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (data.is_valid === false) {
|
if (data.is_valid === false) {
|
||||||
alert.error(data.name+" is only available on https://shuffler.io so far")
|
alert.error(data.name+" is only available on https://shuffler.io so far")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
const triggerLabel = getNextActionName(data.name)
|
const triggerLabel = getNextActionName(data.name)
|
||||||
|
|
||||||
@@ -4929,7 +4931,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const setFolders = () => {
|
const setFolders = () => {
|
||||||
fetch(globalUrl+"/functions/outlook/getFolders?trigger_id="+selectedTrigger.id, {
|
fetch(globalUrl+"/api/v1/triggers/outlook/getFolders?trigger_id="+selectedTrigger.id, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {"content-type": "application/json"},
|
headers: {"content-type": "application/json"},
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
@@ -4942,7 +4944,10 @@ const AngularWorkflow = (props) => {
|
|||||||
return response.json()
|
return response.json()
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
setTriggerFolders(responseJson)
|
if (responseJson !== null && responseJson.success !== false) {
|
||||||
|
setTriggerFolders(responseJson)
|
||||||
|
}
|
||||||
|
|
||||||
if (workflow.triggers[selectedTriggerIndex].parameters.length === 0 && responseJson.length > 0) {
|
if (workflow.triggers[selectedTriggerIndex].parameters.length === 0 && responseJson.length > 0) {
|
||||||
workflow.triggers[selectedTriggerIndex].parameters = [{"value": responseJson[0].displayName, "name": "outlookfolder", "id": responseJson[0].id}]
|
workflow.triggers[selectedTriggerIndex].parameters = [{"value": responseJson[0].displayName, "name": "outlookfolder", "id": responseJson[0].id}]
|
||||||
selectedTrigger.parameters = [{"value": responseJson[0].displayName, "name": "outlookfolder", "id": responseJson[0].id}]
|
selectedTrigger.parameters = [{"value": responseJson[0].displayName, "name": "outlookfolder", "id": responseJson[0].id}]
|
||||||
@@ -4956,7 +4961,7 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getTriggerAuth = () => {
|
const getTriggerAuth = () => {
|
||||||
fetch(globalUrl+"/api/v1/triggers/"+selectedTrigger.id, {
|
fetch(globalUrl+"/api/v1/triggers/outlook/"+selectedTrigger.id, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {"content-type": "application/json"},
|
headers: {"content-type": "application/json"},
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
@@ -4987,15 +4992,22 @@ const AngularWorkflow = (props) => {
|
|||||||
const outlookButton =
|
const outlookButton =
|
||||||
<Button variant="contained" style={{flex: "1",}} onClick={() => {
|
<Button variant="contained" style={{flex: "1",}} onClick={() => {
|
||||||
// When window closes, it should get all the folders for the user from backend
|
// When window closes, it should get all the folders for the user from backend
|
||||||
const redirectUri = "http%3A%2F%2Fshuffler.io"
|
//const redirectUri = "http%3A%2F%2Fshuffler.io"
|
||||||
const url = "https://login.microsoftonline.com/common/oauth2/authorize?client_id=70e37005-c954-4290-b573-d4b94e484336&redirect_uri="+redirectUri+"%2Ffunctions%2Foutlook%2Fregister&resource=https%3A%2F%2Fgraph.microsoft.com&response_type=code&scope=Mail.Read+User.Read+https%3A%2F%2Foutlook.office.com%2Fmail.read&state=workflow_id%3D"+props.match.params.key+"%26trigger_id%3D"+selectedTrigger.id+"%26username%3Drheyix.yt@gmail.com%26type%3Doutlook"
|
//const client_id = "70e37005-c954-4290-b573-d4b94e484336"
|
||||||
|
const redirectUri = isCloud ? "https%3A%2F%2Fshuffler.io%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister" : "http%3A%2F%2Flocalhost:5001%2Fapi%2Fv1%2Ftriggers%2Foutlook%2Fregister"
|
||||||
|
console.log(redirectUri)
|
||||||
|
const client_id = "fd55c175-aa30-4fa6-b303-09a29fb3f750"
|
||||||
|
const username = isCloud ? userdata.username : userdata.id
|
||||||
|
console.log("USER: ", username, userdata)
|
||||||
|
const url = "https://login.microsoftonline.com/common/oauth2/authorize?client_id="+client_id+"&redirect_uri="+redirectUri+"&resource=https%3A%2F%2Fgraph.microsoft.com&response_type=code&scope=Mail.Read+User.Read+https%3A%2F%2Foutlook.office.com%2Fmail.read&state=workflow_id%3D"+props.match.params.key+"%26trigger_id%3D"+selectedTrigger.id+"%26username%3D"+username+"%26type%3Doutlook"
|
||||||
|
console.log("URL: ", url)
|
||||||
|
|
||||||
var newwin = window.open(url, "", "width=200,height=100")
|
var newwin = window.open(url, "", "width=200,height=100")
|
||||||
var data = {}
|
var data = {}
|
||||||
|
|
||||||
// Check whether we got a callback somewhere
|
// Check whether we got a callback somewhere
|
||||||
var id = setInterval(function () {
|
var id = setInterval(function () {
|
||||||
fetch(globalUrl+"/api/v1/triggers/"+selectedTrigger.id, {
|
fetch(globalUrl+"/api/v1/triggers/outlook/"+selectedTrigger.id, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {"content-type": "application/json"},
|
headers: {"content-type": "application/json"},
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
@@ -5040,46 +5052,50 @@ const AngularWorkflow = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
{outlookButton}
|
{outlookButton}
|
||||||
|
|
||||||
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
|
{triggerFolders === undefined || triggerFolders === null ? null :
|
||||||
<div style={{width: "17px", height: "17px", borderRadius: 17 / 2, backgroundColor: "#f85a3e", marginRight: "10px"}}/>
|
<span>
|
||||||
<div style={{flex: "10"}}>
|
<div style={{marginTop: "20px", marginBottom: "7px", display: "flex"}}>
|
||||||
<b>Folders: </b>(hold CTRL to select multiple)
|
<div style={{width: "17px", height: "17px", borderRadius: 17 / 2, backgroundColor: "#f85a3e", marginRight: "10px"}}/>
|
||||||
</div>
|
<div style={{flex: "10"}}>
|
||||||
</div>
|
<b>Folders: </b>(hold CTRL to select multiple)
|
||||||
<Select
|
</div>
|
||||||
multiple
|
</div>
|
||||||
native
|
<Select
|
||||||
rows="10"
|
multiple
|
||||||
value={selectedTrigger.parameters[0].value.split(splitter)}
|
native
|
||||||
style={{backgroundColor: inputColor, color: "white"}}
|
rows="10"
|
||||||
SelectDisplayProps={{
|
value={selectedTrigger.parameters[0].value.split(splitter)}
|
||||||
style: {
|
style={{backgroundColor: inputColor, color: "white"}}
|
||||||
marginLeft: 10,
|
SelectDisplayProps={{
|
||||||
}
|
style: {
|
||||||
}}
|
marginLeft: 10,
|
||||||
onChange={(e) => {
|
}
|
||||||
//setTriggerFolderWrapper(e)
|
}}
|
||||||
setTriggerFolderWrapperMulti(e)
|
onChange={(e) => {
|
||||||
}}
|
//setTriggerFolderWrapper(e)
|
||||||
fullWidth
|
setTriggerFolderWrapperMulti(e)
|
||||||
input={<Input id="select-multiple-native" />}
|
}}
|
||||||
key={selectedTrigger}
|
fullWidth
|
||||||
>
|
input={<Input id="select-multiple-native" />}
|
||||||
{triggerFolders.map(folder => {
|
key={selectedTrigger}
|
||||||
var folderItem = <option key={folder.displayName} value={folder.displayName} style={{marginLeft: "10px", fontSize: "1.2em"}}>
|
>
|
||||||
{folder.displayName}
|
{triggerFolders.map(folder => {
|
||||||
</option>
|
var folderItem = <option key={folder.displayName} value={folder.displayName} style={{marginLeft: "10px", fontSize: "1.2em"}}>
|
||||||
if (folder.childFolderCount > 0) {
|
{folder.displayName}
|
||||||
// Here to handle subfolders sometime later
|
</option>
|
||||||
folderItem =
|
if (folder.childFolderCount > 0) {
|
||||||
<option key={folder.displayName} value={folder.displayName} style={{marginLeft: "10px", fontSize: "1.2em"}}>
|
// Here to handle subfolders sometime later
|
||||||
{folder.displayName}
|
folderItem =
|
||||||
</option>
|
<option key={folder.displayName} value={folder.displayName} style={{marginLeft: "10px", fontSize: "1.2em"}}>
|
||||||
}
|
{folder.displayName}
|
||||||
|
</option>
|
||||||
|
}
|
||||||
|
|
||||||
return folderItem
|
return folderItem
|
||||||
})}
|
})}
|
||||||
</Select>
|
</Select>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
} else if (triggerAuthentication.type === "gmail") {
|
} else if (triggerAuthentication.type === "gmail") {
|
||||||
triggerInfo = "SPECIAL GMAIL"
|
triggerInfo = "SPECIAL GMAIL"
|
||||||
@@ -5578,10 +5594,10 @@ const AngularWorkflow = (props) => {
|
|||||||
if (trigger.id === undefined) {
|
if (trigger.id === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
alert.info("Stopping trigger")
|
alert.info("Deleting mail trigger")
|
||||||
|
|
||||||
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/outlook/"+trigger.id, {
|
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/outlook/"+trigger.id, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
@@ -5616,6 +5632,10 @@ const AngularWorkflow = (props) => {
|
|||||||
const startMailSub = (trigger, triggerindex) => {
|
const startMailSub = (trigger, triggerindex) => {
|
||||||
var folders = []
|
var folders = []
|
||||||
|
|
||||||
|
if (triggerFolders === null || triggerFolders === undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const splitItem = workflow.triggers[selectedTriggerIndex].parameters[0].value.split(splitter)
|
const splitItem = workflow.triggers[selectedTriggerIndex].parameters[0].value.split(splitter)
|
||||||
for (var key in splitItem) {
|
for (var key in splitItem) {
|
||||||
const item = splitItem[key]
|
const item = splitItem[key]
|
||||||
|
|||||||
Reference in New Issue
Block a user