2018-10-09 17:00:01 -04:00
|
|
|
/*
|
2019-04-09 14:39:42 -04:00
|
|
|
* MinIO Cloud Storage, (C) 2018 MinIO, Inc.
|
2018-10-09 17:00:01 -04:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package iampolicy
|
|
|
|
|
|
|
|
import (
|
2020-01-27 17:12:34 -05:00
|
|
|
"github.com/minio/minio/pkg/bucket/policy/condition"
|
2018-10-09 17:00:01 -04:00
|
|
|
"github.com/minio/minio/pkg/wildcard"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Action - policy action.
|
|
|
|
// Refer https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazons3.html
|
|
|
|
// for more information about available actions.
|
|
|
|
type Action string
|
|
|
|
|
|
|
|
const (
|
|
|
|
// AbortMultipartUploadAction - AbortMultipartUpload Rest API action.
|
|
|
|
AbortMultipartUploadAction Action = "s3:AbortMultipartUpload"
|
|
|
|
|
|
|
|
// CreateBucketAction - CreateBucket Rest API action.
|
|
|
|
CreateBucketAction = "s3:CreateBucket"
|
|
|
|
|
|
|
|
// DeleteBucketAction - DeleteBucket Rest API action.
|
|
|
|
DeleteBucketAction = "s3:DeleteBucket"
|
|
|
|
|
2020-04-06 20:51:05 -04:00
|
|
|
// ForceDeleteBucketAction - DeleteBucket Rest API action when x-minio-force-delete flag
|
|
|
|
// is specified.
|
|
|
|
ForceDeleteBucketAction = "s3:ForceDeleteBucket"
|
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// DeleteBucketPolicyAction - DeleteBucketPolicy Rest API action.
|
|
|
|
DeleteBucketPolicyAction = "s3:DeleteBucketPolicy"
|
|
|
|
|
|
|
|
// DeleteObjectAction - DeleteObject Rest API action.
|
|
|
|
DeleteObjectAction = "s3:DeleteObject"
|
|
|
|
|
|
|
|
// GetBucketLocationAction - GetBucketLocation Rest API action.
|
|
|
|
GetBucketLocationAction = "s3:GetBucketLocation"
|
|
|
|
|
|
|
|
// GetBucketNotificationAction - GetBucketNotification Rest API action.
|
|
|
|
GetBucketNotificationAction = "s3:GetBucketNotification"
|
|
|
|
|
|
|
|
// GetBucketPolicyAction - GetBucketPolicy Rest API action.
|
|
|
|
GetBucketPolicyAction = "s3:GetBucketPolicy"
|
|
|
|
|
|
|
|
// GetObjectAction - GetObject Rest API action.
|
|
|
|
GetObjectAction = "s3:GetObject"
|
|
|
|
|
|
|
|
// HeadBucketAction - HeadBucket Rest API action. This action is unused in minio.
|
|
|
|
HeadBucketAction = "s3:HeadBucket"
|
|
|
|
|
|
|
|
// ListAllMyBucketsAction - ListAllMyBuckets (List buckets) Rest API action.
|
|
|
|
ListAllMyBucketsAction = "s3:ListAllMyBuckets"
|
|
|
|
|
|
|
|
// ListBucketAction - ListBucket Rest API action.
|
|
|
|
ListBucketAction = "s3:ListBucket"
|
|
|
|
|
|
|
|
// ListBucketMultipartUploadsAction - ListMultipartUploads Rest API action.
|
|
|
|
ListBucketMultipartUploadsAction = "s3:ListBucketMultipartUploads"
|
|
|
|
|
2020-07-20 15:52:49 -04:00
|
|
|
// ListenNotificationAction - ListenNotification Rest API action.
|
|
|
|
// This is MinIO extension.
|
|
|
|
ListenNotificationAction = "s3:ListenNotification"
|
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// ListenBucketNotificationAction - ListenBucketNotification Rest API action.
|
2019-04-09 14:39:42 -04:00
|
|
|
// This is MinIO extension.
|
2018-10-09 17:00:01 -04:00
|
|
|
ListenBucketNotificationAction = "s3:ListenBucketNotification"
|
|
|
|
|
|
|
|
// ListMultipartUploadPartsAction - ListParts Rest API action.
|
|
|
|
ListMultipartUploadPartsAction = "s3:ListMultipartUploadParts"
|
|
|
|
|
2019-08-09 13:02:41 -04:00
|
|
|
// PutBucketLifecycleAction - PutBucketLifecycle Rest API action.
|
2020-06-23 13:18:32 -04:00
|
|
|
PutBucketLifecycleAction = "s3:PutLifecycleConfiguration"
|
2019-08-09 13:02:41 -04:00
|
|
|
|
|
|
|
// GetBucketLifecycleAction - GetBucketLifecycle Rest API action.
|
2020-06-23 13:18:32 -04:00
|
|
|
GetBucketLifecycleAction = "s3:GetLifecycleConfiguration"
|
2019-08-09 13:02:41 -04:00
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// PutBucketNotificationAction - PutObjectNotification Rest API action.
|
|
|
|
PutBucketNotificationAction = "s3:PutBucketNotification"
|
|
|
|
|
|
|
|
// PutBucketPolicyAction - PutBucketPolicy Rest API action.
|
|
|
|
PutBucketPolicyAction = "s3:PutBucketPolicy"
|
|
|
|
|
|
|
|
// PutObjectAction - PutObject Rest API action.
|
|
|
|
PutObjectAction = "s3:PutObject"
|
|
|
|
|
2020-06-12 23:04:01 -04:00
|
|
|
// DeleteObjectVersionAction - DeleteObjectVersion Rest API action.
|
|
|
|
DeleteObjectVersionAction = "s3:DeleteObjectVersion"
|
|
|
|
|
|
|
|
// DeleteObjectVersionTaggingAction - DeleteObjectVersionTagging Rest API action.
|
|
|
|
DeleteObjectVersionTaggingAction = "s3:DeleteObjectVersionTagging"
|
|
|
|
|
|
|
|
// GetObjectVersionAction - GetObjectVersionAction Rest API action.
|
|
|
|
GetObjectVersionAction = "s3:GetObjectVersion"
|
|
|
|
|
|
|
|
// GetObjectVersionTaggingAction - GetObjectVersionTagging Rest API action.
|
|
|
|
GetObjectVersionTaggingAction = "s3:GetObjectVersionTagging"
|
|
|
|
|
|
|
|
// PutObjectVersionTaggingAction - PutObjectVersionTagging Rest API action.
|
|
|
|
PutObjectVersionTaggingAction = "s3:PutObjectVersionTagging"
|
|
|
|
|
2019-11-20 16:18:09 -05:00
|
|
|
// BypassGovernanceRetentionAction - bypass governance retention for PutObjectRetention, PutObject and DeleteObject Rest API action.
|
|
|
|
BypassGovernanceRetentionAction = "s3:BypassGovernanceRetention"
|
|
|
|
|
|
|
|
// PutObjectRetentionAction - PutObjectRetention Rest API action.
|
|
|
|
PutObjectRetentionAction = "s3:PutObjectRetention"
|
|
|
|
|
|
|
|
// GetObjectRetentionAction - GetObjectRetention, GetObject, HeadObject Rest API action.
|
|
|
|
GetObjectRetentionAction = "s3:GetObjectRetention"
|
|
|
|
|
2020-01-16 18:41:56 -05:00
|
|
|
// GetObjectLegalHoldAction - GetObjectLegalHold, GetObject Rest API action.
|
|
|
|
GetObjectLegalHoldAction = "s3:GetObjectLegalHold"
|
|
|
|
|
|
|
|
// PutObjectLegalHoldAction - PutObjectLegalHold, PutObject Rest API action.
|
|
|
|
PutObjectLegalHoldAction = "s3:PutObjectLegalHold"
|
|
|
|
|
2019-11-20 16:18:09 -05:00
|
|
|
// GetBucketObjectLockConfigurationAction - GetBucketObjectLockConfiguration Rest API action
|
|
|
|
GetBucketObjectLockConfigurationAction = "s3:GetBucketObjectLockConfiguration"
|
|
|
|
|
|
|
|
// PutBucketObjectLockConfigurationAction - PutBucketObjectLockConfiguration Rest API action
|
|
|
|
PutBucketObjectLockConfigurationAction = "s3:PutBucketObjectLockConfiguration"
|
|
|
|
|
2020-05-05 17:18:13 -04:00
|
|
|
// GetBucketTaggingAction - GetBucketTagging Rest API action
|
|
|
|
GetBucketTaggingAction = "s3:GetBucketTagging"
|
|
|
|
|
|
|
|
// PutBucketTaggingAction - PutBucketTagging Rest API action
|
|
|
|
PutBucketTaggingAction = "s3:PutBucketTagging"
|
|
|
|
|
2020-01-20 11:45:59 -05:00
|
|
|
// GetObjectTaggingAction - Get Object Tags API action
|
|
|
|
GetObjectTaggingAction = "s3:GetObjectTagging"
|
|
|
|
|
|
|
|
// PutObjectTaggingAction - Put Object Tags API action
|
|
|
|
PutObjectTaggingAction = "s3:PutObjectTagging"
|
|
|
|
|
|
|
|
// DeleteObjectTaggingAction - Delete Object Tags API action
|
|
|
|
DeleteObjectTaggingAction = "s3:DeleteObjectTagging"
|
|
|
|
|
2020-02-18 13:32:53 -05:00
|
|
|
// PutBucketEncryptionAction - PutBucketEncryption REST API action
|
|
|
|
PutBucketEncryptionAction = "s3:PutEncryptionConfiguration"
|
|
|
|
|
|
|
|
// GetBucketEncryptionAction - GetBucketEncryption REST API action
|
|
|
|
GetBucketEncryptionAction = "s3:GetEncryptionConfiguration"
|
|
|
|
|
2020-06-12 23:04:01 -04:00
|
|
|
// PutBucketVersioningAction - PutBucketVersioning REST API action
|
|
|
|
PutBucketVersioningAction = "s3:PutBucketVersioning"
|
|
|
|
|
|
|
|
// GetBucketVersioningAction - GetBucketVersioning REST API action
|
|
|
|
GetBucketVersioningAction = "s3:GetBucketVersioning"
|
|
|
|
|
2018-10-09 17:00:01 -04:00
|
|
|
// AllActions - all API actions
|
|
|
|
AllActions = "s3:*"
|
|
|
|
)
|
|
|
|
|
|
|
|
// List of all supported actions.
|
|
|
|
var supportedActions = map[Action]struct{}{
|
2019-11-20 16:18:09 -05:00
|
|
|
AbortMultipartUploadAction: {},
|
|
|
|
CreateBucketAction: {},
|
|
|
|
DeleteBucketAction: {},
|
2020-04-06 20:51:05 -04:00
|
|
|
ForceDeleteBucketAction: {},
|
2019-11-20 16:18:09 -05:00
|
|
|
DeleteBucketPolicyAction: {},
|
|
|
|
DeleteObjectAction: {},
|
|
|
|
GetBucketLocationAction: {},
|
|
|
|
GetBucketNotificationAction: {},
|
|
|
|
GetBucketPolicyAction: {},
|
|
|
|
GetObjectAction: {},
|
|
|
|
HeadBucketAction: {},
|
|
|
|
ListAllMyBucketsAction: {},
|
|
|
|
ListBucketAction: {},
|
|
|
|
ListBucketMultipartUploadsAction: {},
|
2020-07-20 15:52:49 -04:00
|
|
|
ListenNotificationAction: {},
|
2019-11-20 16:18:09 -05:00
|
|
|
ListenBucketNotificationAction: {},
|
|
|
|
ListMultipartUploadPartsAction: {},
|
2020-05-15 21:16:45 -04:00
|
|
|
PutBucketLifecycleAction: {},
|
|
|
|
GetBucketLifecycleAction: {},
|
2019-11-20 16:18:09 -05:00
|
|
|
PutBucketNotificationAction: {},
|
|
|
|
PutBucketPolicyAction: {},
|
|
|
|
PutObjectAction: {},
|
2020-05-15 21:16:45 -04:00
|
|
|
BypassGovernanceRetentionAction: {},
|
2019-11-20 16:18:09 -05:00
|
|
|
PutObjectRetentionAction: {},
|
|
|
|
GetObjectRetentionAction: {},
|
2020-01-16 18:41:56 -05:00
|
|
|
GetObjectLegalHoldAction: {},
|
|
|
|
PutObjectLegalHoldAction: {},
|
2019-11-20 16:18:09 -05:00
|
|
|
GetBucketObjectLockConfigurationAction: {},
|
2020-05-15 21:16:45 -04:00
|
|
|
PutBucketObjectLockConfigurationAction: {},
|
2020-05-05 17:18:13 -04:00
|
|
|
GetBucketTaggingAction: {},
|
2020-05-15 21:16:45 -04:00
|
|
|
PutBucketTaggingAction: {},
|
2020-06-12 23:04:01 -04:00
|
|
|
GetObjectVersionAction: {},
|
|
|
|
GetObjectVersionTaggingAction: {},
|
|
|
|
DeleteObjectVersionAction: {},
|
|
|
|
DeleteObjectVersionTaggingAction: {},
|
|
|
|
PutObjectVersionTaggingAction: {},
|
2020-01-20 11:45:59 -05:00
|
|
|
GetObjectTaggingAction: {},
|
|
|
|
PutObjectTaggingAction: {},
|
|
|
|
DeleteObjectTaggingAction: {},
|
2020-02-18 13:32:53 -05:00
|
|
|
PutBucketEncryptionAction: {},
|
|
|
|
GetBucketEncryptionAction: {},
|
2020-06-12 23:04:01 -04:00
|
|
|
PutBucketVersioningAction: {},
|
|
|
|
GetBucketVersioningAction: {},
|
2020-05-15 21:16:45 -04:00
|
|
|
AllActions: {},
|
2020-02-18 13:32:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// List of all supported object actions.
|
|
|
|
var supportedObjectActions = map[Action]struct{}{
|
2020-06-12 23:04:01 -04:00
|
|
|
AllActions: {},
|
|
|
|
AbortMultipartUploadAction: {},
|
|
|
|
DeleteObjectAction: {},
|
|
|
|
GetObjectAction: {},
|
|
|
|
ListMultipartUploadPartsAction: {},
|
|
|
|
PutObjectAction: {},
|
|
|
|
BypassGovernanceRetentionAction: {},
|
|
|
|
PutObjectRetentionAction: {},
|
|
|
|
GetObjectRetentionAction: {},
|
|
|
|
PutObjectLegalHoldAction: {},
|
|
|
|
GetObjectLegalHoldAction: {},
|
|
|
|
GetObjectTaggingAction: {},
|
|
|
|
PutObjectTaggingAction: {},
|
|
|
|
DeleteObjectTaggingAction: {},
|
|
|
|
GetObjectVersionAction: {},
|
|
|
|
GetObjectVersionTaggingAction: {},
|
|
|
|
DeleteObjectVersionAction: {},
|
|
|
|
DeleteObjectVersionTaggingAction: {},
|
|
|
|
PutObjectVersionTaggingAction: {},
|
2018-10-09 17:00:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// isObjectAction - returns whether action is object type or not.
|
|
|
|
func (action Action) isObjectAction() bool {
|
2020-02-18 13:32:53 -05:00
|
|
|
_, ok := supportedObjectActions[action]
|
|
|
|
return ok
|
2018-10-09 17:00:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Match - matches object name with resource pattern.
|
|
|
|
func (action Action) Match(a Action) bool {
|
|
|
|
return wildcard.Match(string(action), string(a))
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsValid - checks if action is valid or not.
|
|
|
|
func (action Action) IsValid() bool {
|
|
|
|
_, ok := supportedActions[action]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
// actionConditionKeyMap - holds mapping of supported condition key for an action.
|
|
|
|
var actionConditionKeyMap = map[Action]condition.KeySet{
|
2018-12-26 20:39:30 -05:00
|
|
|
AllActions: condition.NewKeySet(condition.AllSupportedKeys...),
|
|
|
|
|
2018-12-28 15:18:58 -05:00
|
|
|
AbortMultipartUploadAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
CreateBucketAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
DeleteBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
DeleteObjectAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
GetBucketLocationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
GetBucketNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
GetBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
2018-10-09 17:00:01 -04:00
|
|
|
|
|
|
|
GetObjectAction: condition.NewKeySet(
|
2018-12-28 15:18:58 -05:00
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3XAmzServerSideEncryption,
|
|
|
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
|
|
|
|
HeadBucketAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
ListAllMyBucketsAction: condition.NewKeySet(condition.CommonKeys...),
|
2018-10-09 17:00:01 -04:00
|
|
|
|
|
|
|
ListBucketAction: condition.NewKeySet(
|
2018-12-28 15:18:58 -05:00
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3Prefix,
|
|
|
|
condition.S3Delimiter,
|
|
|
|
condition.S3MaxKeys,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
|
|
|
|
ListBucketMultipartUploadsAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
2020-07-20 15:52:49 -04:00
|
|
|
ListenNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
2018-12-28 15:18:58 -05:00
|
|
|
ListenBucketNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
ListMultipartUploadPartsAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
PutBucketNotificationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
|
|
|
|
PutBucketPolicyAction: condition.NewKeySet(condition.CommonKeys...),
|
2018-10-09 17:00:01 -04:00
|
|
|
|
|
|
|
PutObjectAction: condition.NewKeySet(
|
2018-12-28 15:18:58 -05:00
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3XAmzCopySource,
|
|
|
|
condition.S3XAmzServerSideEncryption,
|
|
|
|
condition.S3XAmzServerSideEncryptionCustomerAlgorithm,
|
|
|
|
condition.S3XAmzMetadataDirective,
|
|
|
|
condition.S3XAmzStorageClass,
|
2020-04-01 03:04:25 -04:00
|
|
|
condition.S3ObjectLockRetainUntilDate,
|
|
|
|
condition.S3ObjectLockMode,
|
|
|
|
condition.S3ObjectLockLegalHold,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
|
2020-04-06 16:44:16 -04:00
|
|
|
// https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html
|
|
|
|
// LockLegalHold is not supported with PutObjectRetentionAction
|
2020-04-01 03:04:25 -04:00
|
|
|
PutObjectRetentionAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3ObjectLockRemainingRetentionDays,
|
|
|
|
condition.S3ObjectLockRetainUntilDate,
|
|
|
|
condition.S3ObjectLockMode,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
|
|
|
|
GetObjectRetentionAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
PutObjectLegalHoldAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3ObjectLockLegalHold,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
GetObjectLegalHoldAction: condition.NewKeySet(condition.CommonKeys...),
|
2020-04-06 16:44:16 -04:00
|
|
|
|
|
|
|
// https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html
|
2020-04-01 03:04:25 -04:00
|
|
|
BypassGovernanceRetentionAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3ObjectLockRemainingRetentionDays,
|
|
|
|
condition.S3ObjectLockRetainUntilDate,
|
|
|
|
condition.S3ObjectLockMode,
|
|
|
|
condition.S3ObjectLockLegalHold,
|
2018-12-28 15:18:58 -05:00
|
|
|
}, condition.CommonKeys...)...),
|
2020-04-06 16:44:16 -04:00
|
|
|
|
2019-11-20 16:18:09 -05:00
|
|
|
GetBucketObjectLockConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
PutBucketObjectLockConfigurationAction: condition.NewKeySet(condition.CommonKeys...),
|
2020-05-05 17:18:13 -04:00
|
|
|
GetBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
PutBucketTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
2020-01-20 11:45:59 -05:00
|
|
|
PutObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
GetObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
DeleteObjectTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
2020-06-12 23:04:01 -04:00
|
|
|
|
|
|
|
PutObjectVersionTaggingAction: condition.NewKeySet(condition.CommonKeys...),
|
|
|
|
GetObjectVersionAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3VersionID,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
GetObjectVersionTaggingAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3VersionID,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
DeleteObjectVersionAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3VersionID,
|
|
|
|
}, condition.CommonKeys...)...),
|
|
|
|
DeleteObjectVersionTaggingAction: condition.NewKeySet(
|
|
|
|
append([]condition.Key{
|
|
|
|
condition.S3VersionID,
|
|
|
|
}, condition.CommonKeys...)...),
|
2018-10-09 17:00:01 -04:00
|
|
|
}
|