diff --git a/satellite/admin/bucket_testplanet_test.go b/satellite/admin/bucket_testplanet_test.go index 946dbbe2d871..535248bd660a 100644 --- a/satellite/admin/bucket_testplanet_test.go +++ b/satellite/admin/bucket_testplanet_test.go @@ -102,6 +102,7 @@ func TestAdminBucketGeofenceAPI(t *testing.T) { Name: b.Name, ProjectID: testCase.project, Created: b.Created, + CreatedBy: b.CreatedBy, Placement: storj.EU, }) require.NoError(t, err, "failed to json encode expected bucket") diff --git a/satellite/buckets/db.go b/satellite/buckets/db.go index 02fcfc2fc803..cef76eabd986 100644 --- a/satellite/buckets/db.go +++ b/satellite/buckets/db.go @@ -35,6 +35,7 @@ type Bucket struct { ID uuid.UUID Name string ProjectID uuid.UUID + CreatedBy uuid.UUID UserAgent []byte Created time.Time PathCipher storj.CipherSuite diff --git a/satellite/console/apikeys.go b/satellite/console/apikeys.go index 46caf7e13e41..f238f7ef1205 100644 --- a/satellite/console/apikeys.go +++ b/satellite/console/apikeys.go @@ -56,6 +56,7 @@ type APIKeyInfo struct { ID uuid.UUID `json:"id"` ProjectID uuid.UUID `json:"projectId"` ProjectPublicID uuid.UUID `json:"projectPublicId"` + CreatedBy uuid.UUID `json:"createdBy"` UserAgent []byte `json:"userAgent"` Name string `json:"name"` Head []byte `json:"-"` diff --git a/satellite/console/consoleweb/consoleapi/apidocs.gen.md b/satellite/console/consoleweb/consoleapi/apidocs.gen.md index fc76f581fd6a..fdc11ec94190 100644 --- a/satellite/console/consoleweb/consoleapi/apidocs.gen.md +++ b/satellite/console/consoleweb/consoleapi/apidocs.gen.md @@ -264,6 +264,7 @@ Gets API keys by project ID id: string // UUID formatted as `00000000-0000-0000-0000-000000000000` projectId: string // UUID formatted as `00000000-0000-0000-0000-000000000000` projectPublicId: string // UUID formatted as `00000000-0000-0000-0000-000000000000` + createdBy: string // UUID formatted as `00000000-0000-0000-0000-000000000000` userAgent: string name: string createdAt: string // Date timestamp formatted as `2006-01-02T15:00:00Z` diff --git a/satellite/console/service.go b/satellite/console/service.go index 70dcec085a05..e44e0bb8591c 100644 --- a/satellite/console/service.go +++ b/satellite/console/service.go @@ -2512,6 +2512,7 @@ func (s *Service) CreateAPIKey(ctx context.Context, projectID uuid.UUID, name st apikey := APIKeyInfo{ Name: name, ProjectID: isMember.project.ID, + CreatedBy: user.ID, Secret: secret, UserAgent: user.UserAgent, } diff --git a/satellite/console/service_test.go b/satellite/console/service_test.go index 07dd3b53a49e..5cb698a94043 100644 --- a/satellite/console/service_test.go +++ b/satellite/console/service_test.go @@ -582,6 +582,13 @@ func TestService(t *testing.T) { require.Equal(t, "console service: project usage: some buckets still exist", err.Error()) }) + t.Run("CreateAPIKey", func(t *testing.T) { + createdAPIKey, _, err := service.CreateAPIKey(userCtx2, up2Proj.ID, "test key") + require.NoError(t, err) + require.NotNil(t, createdAPIKey) + require.Equal(t, up2Proj.OwnerID, createdAPIKey.CreatedBy) + }) + t.Run("GetProjectUsageLimits", func(t *testing.T) { bandwidthLimit := sat.Config.Console.UsageLimits.Bandwidth.Free storageLimit := sat.Config.Console.UsageLimits.Storage.Free diff --git a/satellite/metainfo/endpoint_bucket.go b/satellite/metainfo/endpoint_bucket.go index a0b55265c3fd..fe9e3e2df2cb 100644 --- a/satellite/metainfo/endpoint_bucket.go +++ b/satellite/metainfo/endpoint_bucket.go @@ -203,7 +203,7 @@ func (endpoint *Endpoint) CreateBucket(ctx context.Context, req *pb.BucketCreate return nil, rpcstatus.Error(rpcstatus.ResourceExhausted, fmt.Sprintf("number of allocated buckets (%d) exceeded", endpoint.config.ProjectLimits.MaxBuckets)) } - bucketReq, err := convertProtoToBucket(req, keyInfo.ProjectID) + bucketReq, err := convertProtoToBucket(req, keyInfo) if err != nil { return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error()) } @@ -486,7 +486,7 @@ func getAllowedBuckets(ctx context.Context, header *pb.RequestHeader, action mac return allowedBuckets, err } -func convertProtoToBucket(req *pb.BucketCreateRequest, projectID uuid.UUID) (bucket buckets.Bucket, err error) { +func convertProtoToBucket(req *pb.BucketCreateRequest, keyInfo *console.APIKeyInfo) (bucket buckets.Bucket, err error) { bucketID, err := uuid.New() if err != nil { return buckets.Bucket{}, err @@ -495,7 +495,8 @@ func convertProtoToBucket(req *pb.BucketCreateRequest, projectID uuid.UUID) (buc return buckets.Bucket{ ID: bucketID, Name: string(req.GetName()), - ProjectID: projectID, + ProjectID: keyInfo.ProjectID, + CreatedBy: keyInfo.CreatedBy, }, nil } diff --git a/satellite/metainfo/endpoint_bucket_test.go b/satellite/metainfo/endpoint_bucket_test.go index 046c162f9fe4..41d323e8e632 100644 --- a/satellite/metainfo/endpoint_bucket_test.go +++ b/satellite/metainfo/endpoint_bucket_test.go @@ -302,6 +302,38 @@ func TestBucketCreationWithDefaultPlacement(t *testing.T) { }) } +func TestCraeteBucketWithCreatedBy(t *testing.T) { + testplanet.Run(t, testplanet.Config{ + SatelliteCount: 1, UplinkCount: 1, + }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { + sat := planet.Satellites[0] + service := sat.API.Console.Service + project := planet.Uplinks[0].Projects[0] + + userCtx, err := sat.UserContext(ctx, project.Owner.ID) + require.NoError(t, err) + + apiKeyInfo, apiKey, err := service.CreateAPIKey(userCtx, project.ID, "test key") + require.NoError(t, err) + require.NotNil(t, apiKey) + require.False(t, apiKeyInfo.CreatedBy.IsZero()) + + bucketName := []byte("bucket") + _, err = sat.Metainfo.Endpoint.CreateBucket(ctx, &pb.BucketCreateRequest{ + Header: &pb.RequestHeader{ + ApiKey: apiKey.SerializeRaw(), + }, + Name: bucketName, + }) + require.NoError(t, err) + + bucket, err := sat.API.DB.Buckets().GetBucket(ctx, bucketName, project.ID) + require.NoError(t, err) + require.False(t, bucket.CreatedBy.IsZero()) + require.Equal(t, apiKeyInfo.CreatedBy, bucket.CreatedBy) + }) +} + func TestGetBucketLocation(t *testing.T) { testplanet.Run(t, testplanet.Config{ SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1, diff --git a/satellite/satellitedb/apikeys.go b/satellite/satellitedb/apikeys.go index 391c78a29efa..32164b2421ff 100644 --- a/satellite/satellitedb/apikeys.go +++ b/satellite/satellitedb/apikeys.go @@ -211,6 +211,9 @@ func (keys *apikeys) Create(ctx context.Context, head []byte, info console.APIKe if info.UserAgent != nil { optional.UserAgent = dbx.ApiKey_UserAgent(info.UserAgent) } + if !info.CreatedBy.IsZero() { + optional.CreatedBy = dbx.ApiKey_CreatedBy(info.CreatedBy[:]) + } _, err = keys.methods.Create_ApiKey( ctx, @@ -260,9 +263,18 @@ func apiKeyToAPIKeyInfo(ctx context.Context, key *dbx.ApiKey) (_ *console.APIKey return nil, err } + var createdBy uuid.UUID + if key.CreatedBy != nil { + createdBy, err = uuid.FromBytes(key.CreatedBy) + if err != nil { + return nil, err + } + } + result := &console.APIKeyInfo{ ID: id, ProjectID: projectID, + CreatedBy: createdBy, Name: key.Name, CreatedAt: key.CreatedAt, Head: key.Head, diff --git a/satellite/satellitedb/bucketsdb.go b/satellite/satellitedb/bucketsdb.go index 72738a55e24e..537d8dcfc368 100644 --- a/satellite/satellitedb/bucketsdb.go +++ b/satellite/satellitedb/bucketsdb.go @@ -26,14 +26,13 @@ func (db *bucketsDB) CreateBucket(ctx context.Context, bucket buckets.Bucket) (_ optionalFields := dbx.BucketMetainfo_Create_Fields{} if bucket.UserAgent != nil { - optionalFields = dbx.BucketMetainfo_Create_Fields{ - UserAgent: dbx.BucketMetainfo_UserAgent(bucket.UserAgent), - } + optionalFields.UserAgent = dbx.BucketMetainfo_UserAgent(bucket.UserAgent) } if bucket.Versioning != buckets.VersioningUnsupported { - optionalFields = dbx.BucketMetainfo_Create_Fields{ - Versioning: dbx.BucketMetainfo_Versioning(int(bucket.Versioning)), - } + optionalFields.Versioning = dbx.BucketMetainfo_Versioning(int(bucket.Versioning)) + } + if !bucket.CreatedBy.IsZero() { + optionalFields.CreatedBy = dbx.BucketMetainfo_CreatedBy(bucket.CreatedBy[:]) } optionalFields.Placement = dbx.BucketMetainfo_Placement(int(bucket.Placement)) @@ -342,11 +341,20 @@ func convertDBXtoBucket(dbxBucket *dbx.BucketMetainfo) (bucket buckets.Bucket, e return bucket, buckets.ErrBucket.Wrap(err) } + var createdBy uuid.UUID + if dbxBucket.CreatedBy != nil { + createdBy, err = uuid.FromBytes(dbxBucket.CreatedBy) + if err != nil { + return bucket, buckets.ErrBucket.Wrap(err) + } + } + bucket = buckets.Bucket{ ID: id, Name: string(dbxBucket.Name), ProjectID: project, Created: dbxBucket.CreatedAt, + CreatedBy: createdBy, PathCipher: storj.CipherSuite(dbxBucket.PathCipher), DefaultSegmentsSize: int64(dbxBucket.DefaultSegmentSize), DefaultRedundancyScheme: storj.RedundancyScheme{ diff --git a/web/satellite/src/api/v1.gen.ts b/web/satellite/src/api/v1.gen.ts index 1f0436ca9624..5daa21818d76 100644 --- a/web/satellite/src/api/v1.gen.ts +++ b/web/satellite/src/api/v1.gen.ts @@ -8,6 +8,7 @@ export class APIKeyInfo { id: UUID; projectId: UUID; projectPublicId: UUID; + createdBy: UUID; userAgent: string | null; name: string; createdAt: Time;