testing | dont be recursive for external domains | finalize oauth #5
			
				
			
		
		
		
	|  | @ -1,4 +1,4 @@ | |||
| package api | ||||
| package auth | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/sha256" | ||||
|  | @ -12,13 +12,14 @@ import ( | |||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| 	"golang.org/x/oauth2" | ||||
| ) | ||||
| 
 | ||||
| func StartSessionContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func StartSessionContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		verifier := utils.RandomId() + utils.RandomId() | ||||
| 
 | ||||
| 		sha2 := sha256.New() | ||||
|  | @ -50,8 +51,8 @@ func StartSessionContinuation(context *RequestContext, req *http.Request, resp h | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func InterceptOauthCodeContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func InterceptOauthCodeContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		state := req.URL.Query().Get("state") | ||||
| 		code := req.URL.Query().Get("code") | ||||
| 
 | ||||
|  | @ -127,15 +128,15 @@ func getUserFromAuthHeader(dbConn *sql.DB, bearerToken string) (*database.User, | |||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	apiKey, err := database.GetAPIKey(dbConn, parts[1]) | ||||
| 	typesKey, err := database.GetAPIKey(dbConn, parts[1]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if apiKey == nil { | ||||
| 	if typesKey == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	user, err := database.GetUser(dbConn, apiKey.UserID) | ||||
| 	user, err := database.GetUser(dbConn, typesKey.UserID) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -163,8 +164,8 @@ func getUserFromSession(dbConn *sql.DB, sessionId string) (*database.User, error | |||
| 	return user, nil | ||||
| } | ||||
| 
 | ||||
| func VerifySessionContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func VerifySessionContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		authHeader := req.Header.Get("Authorization") | ||||
| 		user, userErr := getUserFromAuthHeader(context.DBConn, authHeader) | ||||
| 
 | ||||
|  | @ -190,8 +191,8 @@ func VerifySessionContinuation(context *RequestContext, req *http.Request, resp | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func GoLoginContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func GoLoginContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		http.SetCookie(resp, &http.Cookie{ | ||||
| 			Name:     "redirect", | ||||
| 			Value:    req.URL.Path, | ||||
|  | @ -205,8 +206,8 @@ func GoLoginContinuation(context *RequestContext, req *http.Request, resp http.R | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func RefreshSessionContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func RefreshSessionContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		sessionCookie, err := req.Cookie("session") | ||||
| 		if err != nil { | ||||
| 			resp.WriteHeader(http.StatusUnauthorized) | ||||
|  | @ -223,8 +224,8 @@ func RefreshSessionContinuation(context *RequestContext, req *http.Request, resp | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func LogoutContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func LogoutContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		sessionCookie, err := req.Cookie("session") | ||||
| 		if err == nil && sessionCookie.Value != "" { | ||||
| 			_ = database.DeleteSession(context.DBConn, sessionCookie.Value) | ||||
|  | @ -1,23 +1,22 @@ | |||
| package api_test | ||||
| package auth_test | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| func setup() (*sql.DB, *api.RequestContext, func()) { | ||||
| func setup() (*sql.DB, *types.RequestContext, func()) { | ||||
| 	randomDb := utils.RandomId() | ||||
| 
 | ||||
| 	testDb := database.MakeConn(&randomDb) | ||||
| 	database.Migrate(testDb) | ||||
| 
 | ||||
| 	context := &api.RequestContext{ | ||||
| 	context := &types.RequestContext{ | ||||
| 		DBConn:       testDb, | ||||
| 		Args:         &args.Arguments{}, | ||||
| 		TemplateData: &(map[string]interface{}{}), | ||||
|  | @ -30,7 +29,7 @@ func setup() (*sql.DB, *api.RequestContext, func()) { | |||
| } | ||||
| 
 | ||||
| /* | ||||
| todo: test api key creation | ||||
| todo: test types key creation | ||||
| + api key attached to user | ||||
| + user session is unique | ||||
| + goLogin goes to page in cookie | ||||
|  | @ -1,4 +1,4 @@ | |||
| package api | ||||
| package dns | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
|  | @ -9,6 +9,7 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/adapters" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
|  | @ -45,8 +46,8 @@ func userCanFuckWithDNSRecord(dbConn *sql.DB, user *database.User, record *datab | |||
| 	return ownedByUser && userIsOwnerOfDomain | ||||
| } | ||||
| 
 | ||||
| func ListDNSRecordsContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func ListDNSRecordsContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		dnsRecords, err := database.GetUserDNSRecords(context.DBConn, context.User.ID) | ||||
| 		if err != nil { | ||||
| 			log.Println(err) | ||||
|  | @ -59,10 +60,10 @@ func ListDNSRecordsContinuation(context *RequestContext, req *http.Request, resp | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func CreateDNSRecordContinuation(dnsAdapter external_dns.ExternalDNSAdapter) func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 		return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| 			formErrors := FormError{ | ||||
| func CreateDNSRecordContinuation(dnsAdapter external_dns.ExternalDNSAdapter) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 		return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 			formErrors := types.FormError{ | ||||
| 				Errors: []string{}, | ||||
| 			} | ||||
| 
 | ||||
|  | @ -139,9 +140,9 @@ func CreateDNSRecordContinuation(dnsAdapter external_dns.ExternalDNSAdapter) fun | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func DeleteDNSRecordContinuation(dnsAdapter external_dns.ExternalDNSAdapter) func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 		return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func DeleteDNSRecordContinuation(dnsAdapter external_dns.ExternalDNSAdapter) func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 		return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 			recordId := req.FormValue("id") | ||||
| 			record, err := database.GetDNSRecord(context.DBConn, recordId) | ||||
| 			if err != nil { | ||||
|  | @ -1,4 +1,4 @@ | |||
| package api_test | ||||
| package dns_test | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
|  | @ -7,19 +7,26 @@ import ( | |||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api" | ||||
| 	//	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/dns"
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| func setup() (*sql.DB, *api.RequestContext, func()) { | ||||
| func IdContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setup() (*sql.DB, *types.RequestContext, func()) { | ||||
| 	randomDb := utils.RandomId() | ||||
| 
 | ||||
| 	testDb := database.MakeConn(&randomDb) | ||||
| 	database.Migrate(testDb) | ||||
| 
 | ||||
| 	context := &api.RequestContext{ | ||||
| 	context := &types.RequestContext{ | ||||
| 		DBConn:       testDb, | ||||
| 		Args:         &args.Arguments{}, | ||||
| 		TemplateData: &(map[string]interface{}{}), | ||||
|  | @ -35,7 +42,7 @@ func TestThatOwnerCanPutRecordInDomain(t *testing.T) { | |||
| 	db, context, cleanup := setup() | ||||
| 	defer cleanup() | ||||
| 
 | ||||
| 	testUser := &database.User{ | ||||
| 	_ = &database.User{ | ||||
| 		ID:       "test", | ||||
| 		Username: "test", | ||||
| 	} | ||||
|  | @ -49,7 +56,7 @@ func TestThatOwnerCanPutRecordInDomain(t *testing.T) { | |||
| 	} | ||||
| 
 | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		api.PutDNSRecordContinuation(context, r, w)(api.IdContinuation, api.IdContinuation) | ||||
| 		//		dns.CreateDNSRecordContinuation(context, r, w)(IdContinuation, IdContinuation)
 | ||||
| 	})) | ||||
| 	defer ts.Close() | ||||
| 
 | ||||
|  | @ -1,18 +1,15 @@ | |||
| package api | ||||
| package guestbook | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| type HcaptchaArgs struct { | ||||
| 	SiteKey string | ||||
| } | ||||
| 
 | ||||
| func validateGuestbookEntry(entry *database.GuestbookEntry) []string { | ||||
| 	errors := []string{} | ||||
| 
 | ||||
|  | @ -37,12 +34,12 @@ func validateGuestbookEntry(entry *database.GuestbookEntry) []string { | |||
| 	return errors | ||||
| } | ||||
| 
 | ||||
| func SignGuestbookContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func SignGuestbookContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		name := req.FormValue("name") | ||||
| 		message := req.FormValue("message") | ||||
| 
 | ||||
| 		formErrors := FormError{ | ||||
| 		formErrors := types.FormError{ | ||||
| 			Errors: []string{}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -73,8 +70,8 @@ func SignGuestbookContinuation(context *RequestContext, req *http.Request, resp | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func ListGuestbookContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func ListGuestbookContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		entries, err := database.GetGuestbookEntries(context.DBConn) | ||||
| 		if err != nil { | ||||
| 			log.Println(err) | ||||
|  | @ -1,4 +1,4 @@ | |||
| package api_test | ||||
| package guestbook_test | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
|  | @ -7,19 +7,26 @@ import ( | |||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/guestbook" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| func setup() (*sql.DB, *api.RequestContext, func()) { | ||||
| func IdContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setup() (*sql.DB, *types.RequestContext, func()) { | ||||
| 	randomDb := utils.RandomId() | ||||
| 
 | ||||
| 	testDb := database.MakeConn(&randomDb) | ||||
| 	database.Migrate(testDb) | ||||
| 
 | ||||
| 	context := &api.RequestContext{ | ||||
| 	context := &types.RequestContext{ | ||||
| 		DBConn:       testDb, | ||||
| 		Args:         &args.Arguments{}, | ||||
| 		TemplateData: &(map[string]interface{}{}), | ||||
|  | @ -44,7 +51,7 @@ func TestValidGuestbookPutsInDatabase(t *testing.T) { | |||
| 	} | ||||
| 
 | ||||
| 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		api.SignGuestbookContinuation(context, r, w)(api.IdContinuation, api.IdContinuation) | ||||
| 		guestbook.SignGuestbookContinuation(context, r, w)(IdContinuation, IdContinuation) | ||||
| 	})) | ||||
| 	defer ts.Close() | ||||
| 
 | ||||
|  | @ -88,7 +95,7 @@ func TestInvalidGuestbookNotFoundInDatabase(t *testing.T) { | |||
| 	} | ||||
| 
 | ||||
| 	testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		api.SignGuestbookContinuation(context, r, w)(api.IdContinuation, api.IdContinuation) | ||||
| 		guestbook.SignGuestbookContinuation(context, r, w)(IdContinuation, IdContinuation) | ||||
| 	})) | ||||
| 	defer testServer.Close() | ||||
| 
 | ||||
|  | @ -1,12 +1,18 @@ | |||
| package api | ||||
| package hcaptcha | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| ) | ||||
| 
 | ||||
| type HcaptchaArgs struct { | ||||
| 	SiteKey string | ||||
| } | ||||
| 
 | ||||
| func verifyCaptcha(secret, response string) error { | ||||
| 	verifyURL := "https://hcaptcha.com/siteverify" | ||||
| 	body := strings.NewReader("secret=" + secret + "&response=" + response) | ||||
|  | @ -40,8 +46,8 @@ func verifyCaptcha(secret, response string) error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func CaptchaArgsContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func CaptchaArgsContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		(*context.TemplateData)["HcaptchaArgs"] = HcaptchaArgs{ | ||||
| 			SiteKey: context.Args.HcaptchaSiteKey, | ||||
| 		} | ||||
|  | @ -49,14 +55,14 @@ func CaptchaArgsContinuation(context *RequestContext, req *http.Request, resp ht | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func CaptchaVerificationContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func CaptchaVerificationContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		hCaptchaResponse := req.FormValue("h-captcha-response") | ||||
| 		secretKey := context.Args.HcaptchaSecret | ||||
| 
 | ||||
| 		err := verifyCaptcha(secretKey, hCaptchaResponse) | ||||
| 		if err != nil { | ||||
| 			(*context.TemplateData)["FormError"] = FormError{ | ||||
| 			(*context.TemplateData)["FormError"] = types.FormError{ | ||||
| 				Errors: []string{"hCaptcha verification failed"}, | ||||
| 			} | ||||
| 			resp.WriteHeader(http.StatusBadRequest) | ||||
|  | @ -1,32 +1,33 @@ | |||
| package api | ||||
| package keys | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| const MAX_USER_API_KEYS = 5 | ||||
| 
 | ||||
| func ListAPIKeysContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| 		apiKeys, err := database.ListUserAPIKeys(context.DBConn, context.User.ID) | ||||
| func ListAPIKeysContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		typesKeys, err := database.ListUserAPIKeys(context.DBConn, context.User.ID) | ||||
| 		if err != nil { | ||||
| 			log.Println(err) | ||||
| 			resp.WriteHeader(http.StatusInternalServerError) | ||||
| 			return failure(context, req, resp) | ||||
| 		} | ||||
| 
 | ||||
| 		(*context.TemplateData)["APIKeys"] = apiKeys | ||||
| 		(*context.TemplateData)["APIKeys"] = typesKeys | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func CreateAPIKeyContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| 		formErrors := FormError{ | ||||
| func CreateAPIKeyContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		formErrors := types.FormError{ | ||||
| 			Errors: []string{}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -38,7 +39,7 @@ func CreateAPIKeyContinuation(context *RequestContext, req *http.Request, resp h | |||
| 		} | ||||
| 
 | ||||
| 		if numKeys >= MAX_USER_API_KEYS { | ||||
| 			formErrors.Errors = append(formErrors.Errors, "max api keys reached") | ||||
| 			formErrors.Errors = append(formErrors.Errors, "max types keys reached") | ||||
| 		} | ||||
| 
 | ||||
| 		if len(formErrors.Errors) > 0 { | ||||
|  | @ -59,17 +60,17 @@ func CreateAPIKeyContinuation(context *RequestContext, req *http.Request, resp h | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func DeleteAPIKeyContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func DeleteAPIKeyContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		key := req.FormValue("key") | ||||
| 
 | ||||
| 		apiKey, err := database.GetAPIKey(context.DBConn, key) | ||||
| 		typesKey, err := database.GetAPIKey(context.DBConn, key) | ||||
| 		if err != nil { | ||||
| 			log.Println(err) | ||||
| 			resp.WriteHeader(http.StatusInternalServerError) | ||||
| 			return failure(context, req, resp) | ||||
| 		} | ||||
| 		if (apiKey == nil) || (apiKey.UserID != context.User.ID) { | ||||
| 		if (typesKey == nil) || (typesKey.UserID != context.User.ID) { | ||||
| 			resp.WriteHeader(http.StatusUnauthorized) | ||||
| 			return failure(context, req, resp) | ||||
| 		} | ||||
							
								
								
									
										76
									
								
								api/serve.go
								
								
								
								
							
							
						
						
									
										76
									
								
								api/serve.go
								
								
								
								
							|  | @ -8,31 +8,19 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/adapters/cloudflare" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/auth" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/dns" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/guestbook" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/hcaptcha" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/keys" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/template" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils" | ||||
| ) | ||||
| 
 | ||||
| type RequestContext struct { | ||||
| 	DBConn *sql.DB | ||||
| 	Args   *args.Arguments | ||||
| 
 | ||||
| 	Id    string | ||||
| 	Start time.Time | ||||
| 
 | ||||
| 	TemplateData *map[string]interface{} | ||||
| 	User         *database.User | ||||
| } | ||||
| 
 | ||||
| type FormError struct { | ||||
| 	Errors []string | ||||
| } | ||||
| 
 | ||||
| type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain | ||||
| type ContinuationChain func(Continuation, Continuation) ContinuationChain | ||||
| 
 | ||||
| func LogRequestContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, _failure Continuation) ContinuationChain { | ||||
| func LogRequestContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		context.Start = time.Now() | ||||
| 		context.Id = utils.RandomId() | ||||
| 
 | ||||
|  | @ -41,8 +29,8 @@ func LogRequestContinuation(context *RequestContext, req *http.Request, resp htt | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func LogExecutionTimeContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, _failure Continuation) ContinuationChain { | ||||
| func LogExecutionTimeContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		end := time.Now() | ||||
| 
 | ||||
| 		log.Println(context.Id, "took", end.Sub(context.Start)) | ||||
|  | @ -51,22 +39,22 @@ func LogExecutionTimeContinuation(context *RequestContext, req *http.Request, re | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func HealthCheckContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, _failure Continuation) ContinuationChain { | ||||
| func HealthCheckContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		resp.WriteHeader(200) | ||||
| 		resp.Write([]byte("healthy")) | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func FailurePassingContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(_success Continuation, failure Continuation) ContinuationChain { | ||||
| func FailurePassingContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(_success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 		return failure(context, req, resp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func IdContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 	return func(success Continuation, _failure Continuation) ContinuationChain { | ||||
| func IdContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { | ||||
| 		return success(context, req, resp) | ||||
| 	} | ||||
| } | ||||
|  | @ -90,8 +78,8 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { | |||
| 		ZoneId:   argv.CloudflareZone, | ||||
| 	} | ||||
| 
 | ||||
| 	makeRequestContext := func() *RequestContext { | ||||
| 		return &RequestContext{ | ||||
| 	makeRequestContext := func() *types.RequestContext { | ||||
| 		return &types.RequestContext{ | ||||
| 			DBConn:       dbConn, | ||||
| 			Args:         argv, | ||||
| 			TemplateData: &map[string]interface{}{}, | ||||
|  | @ -100,7 +88,7 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { | |||
| 
 | ||||
| 	mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation("home.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(template.TemplateContinuation("home.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { | ||||
|  | @ -110,63 +98,63 @@ func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server { | |||
| 
 | ||||
| 	mux.HandleFunc("GET /login", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(StartSessionContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.StartSessionContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /auth", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(InterceptOauthCodeContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.InterceptOauthCodeContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /logout", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(LogoutContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.LogoutContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /dns", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(ListDNSRecordsContinuation, GoLoginContinuation)(TemplateContinuation("dns.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(dns.ListDNSRecordsContinuation, auth.GoLoginContinuation)(template.TemplateContinuation("dns.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("POST /dns", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(ListDNSRecordsContinuation, GoLoginContinuation)(CreateDNSRecordContinuation(cloudflareAdapter), FailurePassingContinuation)(TemplateContinuation("dns.html", true), TemplateContinuation("dns.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(dns.ListDNSRecordsContinuation, auth.GoLoginContinuation)(dns.CreateDNSRecordContinuation(cloudflareAdapter), FailurePassingContinuation)(template.TemplateContinuation("dns.html", true), template.TemplateContinuation("dns.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("POST /dns/delete", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(DeleteDNSRecordContinuation(cloudflareAdapter), GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(dns.DeleteDNSRecordContinuation(cloudflareAdapter), auth.GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /keys", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(ListAPIKeysContinuation, GoLoginContinuation)(TemplateContinuation("api_keys.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(keys.ListAPIKeysContinuation, auth.GoLoginContinuation)(template.TemplateContinuation("api_keys.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("POST /keys", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CreateAPIKeyContinuation, GoLoginContinuation)(ListAPIKeysContinuation, ListAPIKeysContinuation)(TemplateContinuation("api_keys.html", true), TemplateContinuation("api_keys.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(keys.CreateAPIKeyContinuation, auth.GoLoginContinuation)(keys.ListAPIKeysContinuation, keys.ListAPIKeysContinuation)(template.TemplateContinuation("api_keys.html", true), template.TemplateContinuation("api_keys.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("POST /keys/delete", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(DeleteAPIKeyContinuation, GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(keys.DeleteAPIKeyContinuation, auth.GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /guestbook", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CaptchaArgsContinuation, CaptchaArgsContinuation)(ListGuestbookContinuation, ListGuestbookContinuation)(TemplateContinuation("guestbook.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(hcaptcha.CaptchaArgsContinuation, hcaptcha.CaptchaArgsContinuation)(guestbook.ListGuestbookContinuation, guestbook.ListGuestbookContinuation)(template.TemplateContinuation("guestbook.html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("POST /guestbook", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(CaptchaVerificationContinuation, CaptchaVerificationContinuation)(SignGuestbookContinuation, FailurePassingContinuation)(ListGuestbookContinuation, ListGuestbookContinuation)(CaptchaArgsContinuation, CaptchaArgsContinuation)(TemplateContinuation("guestbook.html", true), TemplateContinuation("guestbook.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(hcaptcha.CaptchaVerificationContinuation, hcaptcha.CaptchaVerificationContinuation)(guestbook.SignGuestbookContinuation, FailurePassingContinuation)(guestbook.ListGuestbookContinuation, guestbook.ListGuestbookContinuation)(hcaptcha.CaptchaArgsContinuation, hcaptcha.CaptchaArgsContinuation)(template.TemplateContinuation("guestbook.html", true), template.TemplateContinuation("guestbook.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	mux.HandleFunc("GET /{name}", func(w http.ResponseWriter, r *http.Request) { | ||||
| 		requestContext := makeRequestContext() | ||||
| 		name := r.PathValue("name") | ||||
| 		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation(name+".html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 		LogRequestContinuation(requestContext, r, w)(auth.VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(template.TemplateContinuation(name+".html", true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) | ||||
| 	}) | ||||
| 
 | ||||
| 	return &http.Server{ | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| package api | ||||
| package template | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
|  | @ -7,9 +7,11 @@ import ( | |||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/api/types" | ||||
| ) | ||||
| 
 | ||||
| func renderTemplate(context *RequestContext, templateName string, showBaseHtml bool) (bytes.Buffer, error) { | ||||
| func renderTemplate(context *types.RequestContext, templateName string, showBaseHtml bool) (bytes.Buffer, error) { | ||||
| 	templatePath := context.Args.TemplatePath | ||||
| 	basePath := templatePath + "/base_empty.html" | ||||
| 	if showBaseHtml { | ||||
|  | @ -41,9 +43,9 @@ func renderTemplate(context *RequestContext, templateName string, showBaseHtml b | |||
| 	return buffer, nil | ||||
| } | ||||
| 
 | ||||
| func TemplateContinuation(path string, showBase bool) Continuation { | ||||
| 	return func(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain { | ||||
| 		return func(success Continuation, failure Continuation) ContinuationChain { | ||||
| func TemplateContinuation(path string, showBase bool) types.Continuation { | ||||
| 	return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { | ||||
| 		return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { | ||||
| 			html, err := renderTemplate(context, path, true) | ||||
| 			if errors.Is(err, os.ErrNotExist) { | ||||
| 				resp.WriteHeader(404) | ||||
|  | @ -0,0 +1,28 @@ | |||
| package types | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args" | ||||
| 	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database" | ||||
| ) | ||||
| 
 | ||||
| type RequestContext struct { | ||||
| 	DBConn *sql.DB | ||||
| 	Args   *args.Arguments | ||||
| 
 | ||||
| 	Id    string | ||||
| 	Start time.Time | ||||
| 
 | ||||
| 	TemplateData *map[string]interface{} | ||||
| 	User         *database.User | ||||
| } | ||||
| 
 | ||||
| type FormError struct { | ||||
| 	Errors []string | ||||
| } | ||||
| 
 | ||||
| type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain | ||||
| type ContinuationChain func(Continuation, Continuation) ContinuationChain | ||||
		Loading…
	
		Reference in New Issue