Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\S3\Crypto;
3
 
4
use Aws\Crypto\AbstractCryptoClientV2;
5
use Aws\Crypto\EncryptionTraitV2;
6
use Aws\Crypto\MetadataEnvelope;
7
use Aws\Crypto\Cipher\CipherBuilderTrait;
8
use Aws\S3\MultipartUploader;
9
use Aws\S3\S3ClientInterface;
10
use GuzzleHttp\Promise;
11
 
12
/**
13
 * Encapsulates the execution of a multipart upload of an encrypted object to S3.
14
 *
15
 * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill
16
 * for encryption since there is no native PHP support. The performance for large
17
 * inputs will be a lot slower than for PHP 7.1+, so upgrading older PHP version
18
 * environments may be necessary to use this effectively.
19
 */
20
class S3EncryptionMultipartUploaderV2 extends MultipartUploader
21
{
22
    use CipherBuilderTrait;
23
    use CryptoParamsTraitV2;
24
    use EncryptionTraitV2;
25
    use UserAgentTrait;
26
 
27
    CONST CRYPTO_VERSION = '2.1';
28
 
29
    /**
30
     * Returns if the passed cipher name is supported for encryption by the SDK.
31
     *
32
     * @param string $cipherName The name of a cipher to verify is registered.
33
     *
34
     * @return bool If the cipher passed is in our supported list.
35
     */
36
    public static function isSupportedCipher($cipherName)
37
    {
38
        return in_array($cipherName, AbstractCryptoClientV2::$supportedCiphers);
39
    }
40
 
41
    private $provider;
42
    private $instructionFileSuffix;
43
    private $strategy;
44
 
45
    /**
46
     * Creates a multipart upload for an S3 object after encrypting it.
47
     *
48
     * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill
49
     * for encryption since there is no native PHP support. The performance for
50
     * large inputs will be a lot slower than for PHP 7.1+, so upgrading older
51
     * PHP version environments may be necessary to use this effectively.
52
     *
53
     * The required configuration options are as follows:
54
     *
55
     * - @MaterialsProvider: (MaterialsProviderV2) Provides Cek, Iv, and Cek
56
     *   encrypting/decrypting for encryption metadata.
57
     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
58
     *   is required. Accepts the following options:
59
     *       - Cipher: (string) gcm
60
     *            See also: AbstractCryptoClientV2::$supportedCiphers
61
     *       - KeySize: (int) 128|256
62
     *            See also: MaterialsProvider::$supportedKeySizes
63
     *       - Aad: (string) Additional authentication data. This option is
64
     *            passed directly to OpenSSL when using gcm.
65
     * - @KmsEncryptionContext: (array) Only required if using
66
     *   KmsMaterialsProviderV2. An associative array of key-value
67
     *   pairs to be added to the encryption context for KMS key encryption. An
68
     *   empty array may be passed if no additional context is desired.
69
     * - bucket: (string) Name of the bucket to which the object is
70
     *   being uploaded.
71
     * - key: (string) Key to use for the object being uploaded.
72
     *
73
     * The optional configuration arguments are as follows:
74
     *
75
     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
76
     *   MetadataEnvelope information. Defaults to using a
77
     *   HeadersMetadataStrategy. Can either be a class implementing
78
     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
79
     *   to default.
80
     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
81
     *   instruction file if an using an InstructionFileMetadataHandler was
82
     *   determined.
83
     * - acl: (string) ACL to set on the object being upload. Objects are
84
     *   private by default.
85
     * - before_complete: (callable) Callback to invoke before the
86
     *   `CompleteMultipartUpload` operation. The callback should have a
87
     *   function signature like `function (Aws\Command $command) {...}`.
88
     * - before_initiate: (callable) Callback to invoke before the
89
     *   `CreateMultipartUpload` operation. The callback should have a function
90
     *   signature like `function (Aws\Command $command) {...}`.
91
     * - before_upload: (callable) Callback to invoke before any `UploadPart`
92
     *   operations. The callback should have a function signature like
93
     *   `function (Aws\Command $command) {...}`.
94
     * - concurrency: (int, default=int(5)) Maximum number of concurrent
95
     *   `UploadPart` operations allowed during the multipart upload.
96
     * - params: (array) An array of key/value parameters that will be applied
97
     *   to each of the sub-commands run by the uploader as a base.
98
     *   Auto-calculated options will override these parameters. If you need
99
     *   more granularity over parameters to each sub-command, use the before_*
100
     *   options detailed above to update the commands directly.
101
     * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when
102
     *   doing a multipart upload. This must between 5 MB and 5 GB, inclusive.
103
     * - state: (Aws\Multipart\UploadState) An object that represents the state
104
     *   of the multipart upload and that is used to resume a previous upload.
105
     *   When this option is provided, the `bucket`, `key`, and `part_size`
106
     *   options are ignored.
107
     *
108
     * @param S3ClientInterface $client Client used for the upload.
109
     * @param mixed             $source Source of the data to upload.
110
     * @param array             $config Configuration used to perform the upload.
111
     */
112
    public function __construct(
113
        S3ClientInterface $client,
114
        $source,
115
        array $config = []
116
    ) {
117
        $this->appendUserAgent($client, 'feat/s3-encrypt/' . self::CRYPTO_VERSION);
118
        $this->client = $client;
119
        $config['params'] = [];
120
        if (!empty($config['bucket'])) {
121
            $config['params']['Bucket'] = $config['bucket'];
122
        }
123
        if (!empty($config['key'])) {
124
            $config['params']['Key'] = $config['key'];
125
        }
126
 
127
        $this->provider = $this->getMaterialsProvider($config);
128
        unset($config['@MaterialsProvider']);
129
 
130
        $this->instructionFileSuffix = $this->getInstructionFileSuffix($config);
131
        unset($config['@InstructionFileSuffix']);
132
        $this->strategy = $this->getMetadataStrategy(
133
            $config,
134
            $this->instructionFileSuffix
135
        );
136
        if ($this->strategy === null) {
137
            $this->strategy = self::getDefaultStrategy();
138
        }
139
        unset($config['@MetadataStrategy']);
140
 
141
        $config['prepare_data_source'] = $this->getEncryptingDataPreparer();
142
 
143
        parent::__construct($client, $source, $config);
144
    }
145
 
146
    private static function getDefaultStrategy()
147
    {
148
        return new HeadersMetadataStrategy();
149
    }
150
 
151
    private function getEncryptingDataPreparer()
152
    {
153
        return function() {
154
            // Defer encryption work until promise is executed
155
            $envelope = new MetadataEnvelope();
156
 
157
            list($this->source, $params) = Promise\Create::promiseFor($this->encrypt(
158
                $this->source,
159
                $this->config ?: [],
160
                $this->provider,
161
                $envelope
162
            ))->then(
163
                function ($bodyStream) use ($envelope) {
164
                    $params = $this->strategy->save(
165
                        $envelope,
166
                        $this->config['params']
167
                    );
168
                    return [$bodyStream, $params];
169
                }
170
            )->wait();
171
 
172
            $this->source->rewind();
173
            $this->config['params'] = $params;
174
        };
175
    }
176
}