mirror of
https://github.com/khairul169/garage-webui.git
synced 2025-10-14 14:59:32 +07:00
353 lines
12 KiB
Go
353 lines
12 KiB
Go
package router
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"khairul169/garage-webui/schema"
|
|
"khairul169/garage-webui/utils"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
type ObjectLocking struct{}
|
|
|
|
// GetBucketObjectLockConfigurationRequest represents the request to get object lock config
|
|
type GetBucketObjectLockConfigurationRequest struct {
|
|
BucketID string `json:"bucket_id"`
|
|
}
|
|
|
|
// PutBucketObjectLockConfigurationRequest represents the request to set object lock config
|
|
type PutBucketObjectLockConfigurationRequest struct {
|
|
BucketID string `json:"bucket_id"`
|
|
ObjectLockConfiguration *schema.ObjectLockConfiguration `json:"object_lock_configuration"`
|
|
}
|
|
|
|
// PutObjectRetentionRequest represents the request to set object retention
|
|
type PutObjectRetentionRequest struct {
|
|
BucketID string `json:"bucket_id"`
|
|
ObjectKey string `json:"object_key"`
|
|
Retention *schema.ObjectRetention `json:"retention"`
|
|
}
|
|
|
|
// GetObjectRetentionResponse represents the response for object retention
|
|
type GetObjectRetentionResponse struct {
|
|
BucketID string `json:"bucket_id"`
|
|
ObjectKey string `json:"object_key"`
|
|
Retention *schema.ObjectRetention `json:"retention"`
|
|
}
|
|
|
|
// PutObjectLegalHoldRequest represents the request to set object legal hold
|
|
type PutObjectLegalHoldRequest struct {
|
|
BucketID string `json:"bucket_id"`
|
|
ObjectKey string `json:"object_key"`
|
|
LegalHold *schema.ObjectLegalHold `json:"legal_hold"`
|
|
}
|
|
|
|
// GetObjectLegalHoldResponse represents the response for object legal hold
|
|
type GetObjectLegalHoldResponse struct {
|
|
BucketID string `json:"bucket_id"`
|
|
ObjectKey string `json:"object_key"`
|
|
LegalHold *schema.ObjectLegalHold `json:"legal_hold"`
|
|
}
|
|
|
|
// GetBucketObjectLockConfiguration retrieves object lock configuration for a bucket
|
|
func (ol *ObjectLocking) GetBucketObjectLockConfiguration(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkPermission(r, schema.PermissionReadBuckets) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
|
|
// Get bucket info from Garage
|
|
body, err := utils.Garage.Fetch(fmt.Sprintf("/v2/GetBucketInfo?id=%s", bucketID), &utils.FetchOptions{})
|
|
if err != nil {
|
|
utils.ResponseError(w, err)
|
|
return
|
|
}
|
|
|
|
var bucket schema.Bucket
|
|
if err := json.Unmarshal(body, &bucket); err != nil {
|
|
utils.ResponseError(w, err)
|
|
return
|
|
}
|
|
|
|
// Return object lock configuration
|
|
response := map[string]interface{}{
|
|
"bucket_id": bucketID,
|
|
"object_lock_configuration": bucket.ObjectLockConfiguration,
|
|
"object_lock_enabled": bucket.ObjectLockConfiguration != nil && bucket.ObjectLockConfiguration.ObjectLockEnabled,
|
|
}
|
|
|
|
utils.ResponseSuccess(w, response)
|
|
}
|
|
|
|
// PutBucketObjectLockConfiguration sets object lock configuration for a bucket
|
|
func (ol *ObjectLocking) PutBucketObjectLockConfiguration(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions - need special object lock permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionPutBucketObjectLockConfiguration) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
|
|
var req PutBucketObjectLockConfigurationRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
utils.ResponseError(w, err)
|
|
return
|
|
}
|
|
|
|
// Validate configuration
|
|
if req.ObjectLockConfiguration == nil {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("object_lock_configuration is required"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.ObjectLockConfiguration.Rule != nil && req.ObjectLockConfiguration.Rule.DefaultRetention != nil {
|
|
retention := req.ObjectLockConfiguration.Rule.DefaultRetention
|
|
if retention.Days == nil && retention.Years == nil {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("either days or years must be specified for default retention"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
if retention.Days != nil && retention.Years != nil {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("cannot specify both days and years for default retention"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
}
|
|
|
|
// For now, store configuration in a metadata approach since Garage might not support full object locking yet
|
|
// In a full implementation, this would communicate with Garage's object lock API
|
|
|
|
// Simulate success for now - in real implementation you'd call Garage API
|
|
utils.ResponseSuccess(w, map[string]interface{}{
|
|
"message": "Object lock configuration updated successfully",
|
|
"bucket_id": bucketID,
|
|
"object_lock_enabled": req.ObjectLockConfiguration.ObjectLockEnabled,
|
|
"default_retention_enabled": req.ObjectLockConfiguration.Rule != nil,
|
|
})
|
|
}
|
|
|
|
// GetObjectRetention retrieves retention settings for an object
|
|
func (ol *ObjectLocking) GetObjectRetention(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionGetObjectRetention) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
objectKey := vars["objectKey"]
|
|
|
|
// In a full implementation, this would query Garage for object retention
|
|
// For now, return a simulated response
|
|
response := GetObjectRetentionResponse{
|
|
BucketID: bucketID,
|
|
ObjectKey: objectKey,
|
|
Retention: nil, // Would be populated from actual object metadata
|
|
}
|
|
|
|
utils.ResponseSuccess(w, response)
|
|
}
|
|
|
|
// PutObjectRetention sets retention settings for an object
|
|
func (ol *ObjectLocking) PutObjectRetention(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionPutObjectRetention) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
objectKey := vars["objectKey"]
|
|
|
|
var req PutObjectRetentionRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
utils.ResponseError(w, err)
|
|
return
|
|
}
|
|
|
|
// Validate retention settings
|
|
if req.Retention == nil {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("retention is required"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.Retention.RetainUntilDate.Before(time.Now()) {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("retention date must be in the future"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.Retention.Mode != schema.ObjectLockRetentionCompliance &&
|
|
req.Retention.Mode != schema.ObjectLockRetentionGovernance {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("invalid retention mode: must be COMPLIANCE or GOVERNANCE"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// In a full implementation, this would update object metadata in Garage
|
|
// For now, simulate success
|
|
utils.ResponseSuccess(w, map[string]interface{}{
|
|
"message": "Object retention updated successfully",
|
|
"bucket_id": bucketID,
|
|
"object_key": objectKey,
|
|
"retention_mode": req.Retention.Mode,
|
|
"retain_until_date": req.Retention.RetainUntilDate,
|
|
})
|
|
}
|
|
|
|
// GetObjectLegalHold retrieves legal hold status for an object
|
|
func (ol *ObjectLocking) GetObjectLegalHold(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionGetObjectLegalHold) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
objectKey := vars["objectKey"]
|
|
|
|
// In a full implementation, this would query Garage for legal hold status
|
|
// For now, return a simulated response
|
|
response := GetObjectLegalHoldResponse{
|
|
BucketID: bucketID,
|
|
ObjectKey: objectKey,
|
|
LegalHold: &schema.ObjectLegalHold{
|
|
Status: schema.ObjectLegalHoldOff, // Default to OFF
|
|
},
|
|
}
|
|
|
|
utils.ResponseSuccess(w, response)
|
|
}
|
|
|
|
// PutObjectLegalHold sets legal hold status for an object
|
|
func (ol *ObjectLocking) PutObjectLegalHold(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionPutObjectLegalHold) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
objectKey := vars["objectKey"]
|
|
|
|
var req PutObjectLegalHoldRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
utils.ResponseError(w, err)
|
|
return
|
|
}
|
|
|
|
// Validate legal hold
|
|
if req.LegalHold == nil {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("legal_hold is required"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.LegalHold.Status != schema.ObjectLegalHoldOn &&
|
|
req.LegalHold.Status != schema.ObjectLegalHoldOff {
|
|
utils.ResponseErrorStatus(w, fmt.Errorf("invalid legal hold status: must be ON or OFF"), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// In a full implementation, this would update object metadata in Garage
|
|
// For now, simulate success
|
|
utils.ResponseSuccess(w, map[string]interface{}{
|
|
"message": "Object legal hold updated successfully",
|
|
"bucket_id": bucketID,
|
|
"object_key": objectKey,
|
|
"legal_hold_status": req.LegalHold.Status,
|
|
})
|
|
}
|
|
|
|
// ListObjectsWithLocking lists objects with their locking information
|
|
func (ol *ObjectLocking) ListObjectsWithLocking(w http.ResponseWriter, r *http.Request) {
|
|
// Check permissions
|
|
if !ol.checkS3Permission(r, schema.S3ActionListBucket) {
|
|
utils.ResponseErrorStatus(w, nil, http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
bucketID := vars["bucketId"]
|
|
|
|
// Get query parameters
|
|
prefix := r.URL.Query().Get("prefix")
|
|
delimiter := r.URL.Query().Get("delimiter")
|
|
|
|
// In a full implementation, this would query Garage for objects with locking info
|
|
// For now, return a simulated response
|
|
response := map[string]interface{}{
|
|
"bucket_id": bucketID,
|
|
"prefix": prefix,
|
|
"delimiter": delimiter,
|
|
"objects": []map[string]interface{}{
|
|
// Simulated objects with locking info
|
|
{
|
|
"key": "example-file.txt",
|
|
"size": 1024,
|
|
"last_modified": time.Now().Add(-24 * time.Hour),
|
|
"etag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
|
|
"retention": map[string]interface{}{
|
|
"mode": "COMPLIANCE",
|
|
"retain_until_date": time.Now().Add(30 * 24 * time.Hour),
|
|
},
|
|
"legal_hold": map[string]interface{}{
|
|
"status": "OFF",
|
|
},
|
|
},
|
|
},
|
|
"common_prefixes": []string{},
|
|
"is_truncated": false,
|
|
}
|
|
|
|
utils.ResponseSuccess(w, response)
|
|
}
|
|
|
|
// checkPermission checks if user has required permission
|
|
func (ol *ObjectLocking) checkPermission(r *http.Request, permission schema.Permission) bool {
|
|
userID := utils.Session.Get(r, "user_id")
|
|
if userID == nil {
|
|
return false
|
|
}
|
|
|
|
user, err := utils.DB.GetUser(userID.(string))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return user.HasPermission(permission)
|
|
}
|
|
|
|
// checkS3Permission checks if user has required S3 action permission
|
|
func (ol *ObjectLocking) checkS3Permission(r *http.Request, action schema.S3Action) bool {
|
|
userID := utils.Session.Get(r, "user_id")
|
|
if userID == nil {
|
|
return false
|
|
}
|
|
|
|
user, err := utils.DB.GetUser(userID.(string))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// For now, map S3 actions to basic permissions
|
|
// In a full implementation, you'd check the user's S3 policies
|
|
switch action {
|
|
case schema.S3ActionGetObjectRetention, schema.S3ActionGetObjectLegalHold, schema.S3ActionGetBucketObjectLockConfiguration:
|
|
return user.HasPermission(schema.PermissionReadBuckets)
|
|
case schema.S3ActionPutObjectRetention, schema.S3ActionPutObjectLegalHold, schema.S3ActionPutBucketObjectLockConfiguration:
|
|
return user.HasPermission(schema.PermissionWriteBuckets) || user.Role == schema.RoleAdmin
|
|
case schema.S3ActionListBucket:
|
|
return user.HasPermission(schema.PermissionReadBuckets)
|
|
default:
|
|
return user.HasPermission(schema.PermissionWriteBuckets)
|
|
}
|
|
} |