2023-04-18 17:37:51 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2023-04-19 13:07:46 +00:00
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
|
2023-04-19 12:58:39 +00:00
|
|
|
"github.com/gorilla/mux"
|
2023-04-19 13:07:46 +00:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
2023-04-18 17:37:51 +00:00
|
|
|
)
|
|
|
|
|
2023-04-18 20:45:04 +00:00
|
|
|
func gadmin() (*garage.APIClient, context.Context) {
|
2023-04-19 13:07:46 +00:00
|
|
|
// Set Host and other parameters
|
|
|
|
configuration := garage.NewConfiguration()
|
|
|
|
configuration.Host = config.S3AdminEndpoint
|
2023-04-18 20:45:04 +00:00
|
|
|
|
2023-04-19 13:07:46 +00:00
|
|
|
// We can now generate a client
|
|
|
|
client := garage.NewAPIClient(configuration)
|
2023-04-18 20:45:04 +00:00
|
|
|
|
2023-04-19 13:07:46 +00:00
|
|
|
// Authentication is handled through the context pattern
|
|
|
|
ctx := context.WithValue(context.Background(), garage.ContextAccessToken, config.S3AdminToken)
|
|
|
|
return client, ctx
|
2023-04-18 20:45:04 +00:00
|
|
|
}
|
|
|
|
|
2023-04-19 09:36:13 +00:00
|
|
|
func grgCreateKey(name string) (*garage.KeyInfo, error) {
|
2023-04-19 13:07:46 +00:00
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
kr := garage.AddKeyRequest{Name: &name}
|
|
|
|
resp, _, err := client.KeyApi.AddKey(ctx).AddKeyRequest(kr).Execute()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
2023-04-19 09:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func grgGetKey(accessKey string) (*garage.KeyInfo, error) {
|
2023-04-19 13:07:46 +00:00
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
resp, _, err := client.KeyApi.GetKey(ctx, accessKey).Execute()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
2023-04-19 09:36:13 +00:00
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func grgCreateBucket(bucket string) (*garage.BucketInfo, error) {
|
2023-04-19 13:07:46 +00:00
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
br := garage.NewCreateBucketRequest()
|
|
|
|
br.SetGlobalAlias(bucket)
|
|
|
|
|
|
|
|
// Create Bucket
|
|
|
|
binfo, _, err := client.BucketApi.CreateBucket(ctx).CreateBucketRequest(*br).Execute()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-09-25 17:07:07 +00:00
|
|
|
return binfo, nil
|
|
|
|
}
|
|
|
|
|
2024-02-12 18:19:41 +00:00
|
|
|
func grgCreateLocalBucket(bucket, gkey string) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
is_true := true
|
|
|
|
is_false := false
|
|
|
|
|
|
|
|
la := garage.CreateBucketRequestLocalAlias {
|
|
|
|
AccessKeyId: &gkey,
|
|
|
|
Alias: &bucket,
|
|
|
|
Allow: &garage.CreateBucketRequestLocalAliasAllow {
|
|
|
|
Read: &is_true,
|
|
|
|
Write: &is_true,
|
|
|
|
Owner: &is_false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
br := garage.NewCreateBucketRequest()
|
|
|
|
br.SetLocalAlias(la)
|
|
|
|
|
|
|
|
binfo, _, err := client.BucketApi.CreateBucket(ctx).CreateBucketRequest(*br).Execute()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return binfo, nil
|
|
|
|
}
|
|
|
|
|
2023-09-26 06:40:41 +00:00
|
|
|
func grgAllowKeyOnBucket(bid, gkey string) (*garage.BucketInfo, error) {
|
2023-09-25 17:07:07 +00:00
|
|
|
client, ctx := gadmin()
|
2023-04-19 13:07:46 +00:00
|
|
|
|
|
|
|
// Allow user's key
|
|
|
|
ar := garage.AllowBucketKeyRequest{
|
2023-09-25 17:07:07 +00:00
|
|
|
BucketId: bid,
|
2023-04-19 13:07:46 +00:00
|
|
|
AccessKeyId: gkey,
|
|
|
|
Permissions: *garage.NewAllowBucketKeyRequestPermissions(true, true, true),
|
|
|
|
}
|
2023-09-25 17:07:07 +00:00
|
|
|
binfo, _, err := client.BucketApi.AllowBucketKey(ctx).AllowBucketKeyRequest(ar).Execute()
|
2023-04-19 13:07:46 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
return binfo, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func allowWebsiteDefault() *garage.UpdateBucketRequestWebsiteAccess {
|
2023-04-19 13:07:46 +00:00
|
|
|
wr := garage.NewUpdateBucketRequestWebsiteAccess()
|
|
|
|
wr.SetEnabled(true)
|
|
|
|
wr.SetIndexDocument("index.html")
|
|
|
|
wr.SetErrorDocument("error.html")
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
return wr
|
|
|
|
}
|
2023-04-19 13:07:46 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func grgUpdateBucket(bid string, ur *garage.UpdateBucketRequest) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
2023-04-19 13:07:46 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
binfo, _, err := client.BucketApi.UpdateBucket(ctx, bid).UpdateBucketRequest(*ur).Execute()
|
2023-04-19 13:07:46 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("%+v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return updated binfo
|
|
|
|
return binfo, nil
|
2023-04-19 12:58:39 +00:00
|
|
|
}
|
|
|
|
|
2023-09-15 16:25:37 +00:00
|
|
|
func grgAddGlobalAlias(bid, alias string) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
resp, _, err := client.BucketApi.PutBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func grgAddLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
resp, _, err := client.BucketApi.PutBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func grgDelGlobalAlias(bid, alias string) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
resp, _, err := client.BucketApi.DeleteBucketGlobalAlias(ctx).Id(bid).Alias(alias).Execute()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func grgDelLocalAlias(bid, key, alias string) (*garage.BucketInfo, error) {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
|
|
|
resp, _, err := client.BucketApi.DeleteBucketLocalAlias(ctx).Id(bid).AccessKeyId(key).Alias(alias).Execute()
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2023-04-19 12:58:39 +00:00
|
|
|
func grgGetBucket(bid string) (*garage.BucketInfo, error) {
|
2023-04-19 13:07:46 +00:00
|
|
|
client, ctx := gadmin()
|
2023-04-19 12:58:39 +00:00
|
|
|
|
2023-04-19 13:07:46 +00:00
|
|
|
resp, _, err := client.BucketApi.GetBucketInfo(ctx, bid).Execute()
|
|
|
|
if err != nil {
|
2023-09-15 16:25:37 +00:00
|
|
|
log.Println(err)
|
2023-04-19 13:07:46 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return resp, nil
|
2023-04-19 12:58:39 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-09-25 20:00:46 +00:00
|
|
|
func grgDeleteBucket(bid string) error {
|
|
|
|
client, ctx := gadmin()
|
|
|
|
|
2023-09-26 06:40:41 +00:00
|
|
|
_, err := client.BucketApi.DeleteBucket(ctx, bid).Execute()
|
|
|
|
if err != nil {
|
2023-09-25 20:00:46 +00:00
|
|
|
log.Println(err)
|
2023-09-26 06:40:41 +00:00
|
|
|
}
|
2023-09-25 20:00:46 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-25 13:35:54 +00:00
|
|
|
// --- Start page rendering functions
|
2023-04-18 17:37:51 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func handleWebsiteConfigure(w http.ResponseWriter, r *http.Request) {
|
2023-09-25 13:35:54 +00:00
|
|
|
user := RequireUserHtml(w, r)
|
|
|
|
if user == nil {
|
2023-04-19 13:07:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
tKey := getTemplate("garage_key.html")
|
2023-09-25 13:35:54 +00:00
|
|
|
tKey.Execute(w, user)
|
2023-04-19 10:17:27 +00:00
|
|
|
}
|
2023-04-19 13:07:46 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func handleWebsiteList(w http.ResponseWriter, r *http.Request) {
|
2023-09-25 13:35:54 +00:00
|
|
|
user := RequireUserHtml(w, r)
|
|
|
|
if user == nil {
|
2023-04-19 13:07:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
ctrl, err := NewWebsiteController(user)
|
2023-09-26 06:40:41 +00:00
|
|
|
if err != nil {
|
2023-09-25 17:07:07 +00:00
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-09-26 06:40:41 +00:00
|
|
|
return
|
2023-09-25 17:07:07 +00:00
|
|
|
}
|
|
|
|
|
2023-09-26 06:40:30 +00:00
|
|
|
if len(ctrl.PrettyList) > 0 {
|
|
|
|
http.Redirect(w, r, "/website/inspect/"+ctrl.PrettyList[0], http.StatusFound)
|
2023-09-25 17:07:07 +00:00
|
|
|
} else {
|
|
|
|
http.Redirect(w, r, "/website/new", http.StatusFound)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type WebsiteNewTpl struct {
|
2023-09-25 20:00:46 +00:00
|
|
|
Ctrl *WebsiteController
|
2023-09-26 06:40:41 +00:00
|
|
|
Err error
|
2023-04-18 17:37:51 +00:00
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func handleWebsiteNew(w http.ResponseWriter, r *http.Request) {
|
2023-09-25 13:35:54 +00:00
|
|
|
user := RequireUserHtml(w, r)
|
|
|
|
if user == nil {
|
2023-04-19 13:07:46 +00:00
|
|
|
return
|
|
|
|
}
|
2023-04-19 12:58:39 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
ctrl, err := NewWebsiteController(user)
|
2023-09-26 06:40:41 +00:00
|
|
|
if err != nil {
|
2023-09-25 17:07:07 +00:00
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-09-26 06:40:41 +00:00
|
|
|
return
|
2023-09-25 17:07:07 +00:00
|
|
|
}
|
|
|
|
|
2023-09-25 20:00:46 +00:00
|
|
|
tpl := &WebsiteNewTpl{ctrl, nil}
|
2023-09-25 17:07:07 +00:00
|
|
|
|
2023-04-19 13:07:46 +00:00
|
|
|
tWebsiteNew := getTemplate("garage_website_new.html")
|
2023-04-19 12:58:39 +00:00
|
|
|
if r.Method == "POST" {
|
2023-04-19 13:07:46 +00:00
|
|
|
r.ParseForm()
|
2023-04-19 12:58:39 +00:00
|
|
|
|
|
|
|
bucket := strings.Join(r.Form["bucket"], "")
|
2023-04-19 13:07:46 +00:00
|
|
|
if bucket == "" {
|
|
|
|
bucket = strings.Join(r.Form["bucket2"], "")
|
|
|
|
}
|
2023-09-25 13:35:54 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
view, err := ctrl.Create(bucket)
|
2023-04-19 13:07:46 +00:00
|
|
|
if err != nil {
|
2023-09-25 20:00:46 +00:00
|
|
|
tpl.Err = err
|
2023-09-25 17:07:07 +00:00
|
|
|
tWebsiteNew.Execute(w, tpl)
|
2023-09-25 20:00:46 +00:00
|
|
|
return
|
2023-04-19 13:07:46 +00:00
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound)
|
2023-04-19 13:07:46 +00:00
|
|
|
return
|
|
|
|
}
|
2023-04-19 12:58:39 +00:00
|
|
|
|
2023-09-25 20:00:46 +00:00
|
|
|
tWebsiteNew.Execute(w, tpl)
|
2023-04-18 17:37:51 +00:00
|
|
|
}
|
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
type WebsiteInspectTpl struct {
|
2023-09-26 06:40:30 +00:00
|
|
|
Describe *WebsiteDescribe
|
2023-09-26 06:40:41 +00:00
|
|
|
View *WebsiteView
|
|
|
|
Err error
|
2023-04-19 12:58:39 +00:00
|
|
|
}
|
2023-04-19 13:07:46 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
func handleWebsiteInspect(w http.ResponseWriter, r *http.Request) {
|
2023-09-25 20:00:46 +00:00
|
|
|
var processErr error
|
|
|
|
|
2023-09-25 13:35:54 +00:00
|
|
|
user := RequireUserHtml(w, r)
|
|
|
|
if user == nil {
|
2023-04-19 13:07:46 +00:00
|
|
|
return
|
|
|
|
}
|
2023-04-19 12:58:39 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
ctrl, err := NewWebsiteController(user)
|
2023-09-26 06:40:41 +00:00
|
|
|
if err != nil {
|
2023-09-25 17:07:07 +00:00
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-09-26 06:40:41 +00:00
|
|
|
return
|
2023-09-25 17:07:07 +00:00
|
|
|
}
|
2023-09-25 13:35:54 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
bucketName := mux.Vars(r)["bucket"]
|
2023-09-25 20:00:46 +00:00
|
|
|
|
|
|
|
if r.Method == "POST" {
|
|
|
|
r.ParseForm()
|
2023-09-26 06:40:41 +00:00
|
|
|
action := strings.Join(r.Form["action"], "")
|
2023-09-25 20:00:46 +00:00
|
|
|
switch action {
|
2023-09-26 06:40:41 +00:00
|
|
|
case "increase_quota":
|
|
|
|
_, processErr = ctrl.Patch(bucketName, &WebsitePatch{Size: &user.Quota.WebsiteSizeBursted})
|
|
|
|
case "delete_bucket":
|
|
|
|
processErr = ctrl.Delete(bucketName)
|
2023-10-17 16:33:11 +00:00
|
|
|
if processErr == nil {
|
|
|
|
http.Redirect(w, r, "/website", http.StatusFound)
|
|
|
|
}
|
2023-09-26 06:40:41 +00:00
|
|
|
default:
|
|
|
|
processErr = fmt.Errorf("Unknown action")
|
2023-09-25 20:00:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-09-26 06:40:41 +00:00
|
|
|
|
2023-09-25 17:07:07 +00:00
|
|
|
view, err := ctrl.Inspect(bucketName)
|
2023-04-19 13:07:46 +00:00
|
|
|
if err != nil {
|
2023-09-25 17:07:07 +00:00
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-09-26 06:40:41 +00:00
|
|
|
return
|
2023-04-19 13:07:46 +00:00
|
|
|
}
|
2023-09-26 06:40:41 +00:00
|
|
|
|
2023-09-26 06:40:30 +00:00
|
|
|
describe, err := ctrl.Describe()
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-09-26 06:40:41 +00:00
|
|
|
return
|
2023-09-26 06:40:30 +00:00
|
|
|
}
|
2023-04-19 13:07:46 +00:00
|
|
|
|
2023-09-26 06:40:41 +00:00
|
|
|
tpl := &WebsiteInspectTpl{describe, view, processErr}
|
2023-04-19 13:07:46 +00:00
|
|
|
|
|
|
|
tWebsiteInspect := getTemplate("garage_website_inspect.html")
|
2023-09-25 17:07:07 +00:00
|
|
|
tWebsiteInspect.Execute(w, &tpl)
|
2023-04-18 17:37:51 +00:00
|
|
|
}
|
2023-10-17 16:33:11 +00:00
|
|
|
|
|
|
|
func handleWebsiteVhost(w http.ResponseWriter, r *http.Request) {
|
|
|
|
var processErr error
|
|
|
|
|
|
|
|
user := RequireUserHtml(w, r)
|
|
|
|
if user == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrl, err := NewWebsiteController(user)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
bucketName := mux.Vars(r)["bucket"]
|
|
|
|
|
|
|
|
if r.Method == "POST" {
|
|
|
|
r.ParseForm()
|
|
|
|
|
|
|
|
bucket := strings.Join(r.Form["bucket"], "")
|
|
|
|
if bucket == "" {
|
|
|
|
bucket = strings.Join(r.Form["bucket2"], "")
|
|
|
|
}
|
|
|
|
|
|
|
|
view, processErr := ctrl.Patch(bucketName, &WebsitePatch{Vhost: &bucket})
|
|
|
|
if processErr == nil {
|
|
|
|
http.Redirect(w, r, "/website/inspect/"+view.Name.Pretty, http.StatusFound)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
view, err := ctrl.Inspect(bucketName)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
describe, err := ctrl.Describe()
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
tpl := &WebsiteInspectTpl{describe, view, processErr}
|
|
|
|
tWebsiteEdit := getTemplate("garage_website_edit.html")
|
|
|
|
tWebsiteEdit.Execute(w, &tpl)
|
|
|
|
}
|