Browse Source

doc: argument types for crypto methods

Refs: https://github.com/nodejs/node/issues/9399
PR-URL: https://github.com/nodejs/node/pull/11799
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
v6
Amelia Clarke 8 years ago
committed by James M Snell
parent
commit
73e2d0bce6
  1. 219
      doc/api/crypto.md

219
doc/api/crypto.md

@ -62,11 +62,9 @@ const cert2 = crypto.Certificate();
<!-- YAML
added: v0.11.8
-->
The `spkac` data structure includes a public key and a challenge. The
`certificate.exportChallenge()` returns the challenge component in the
form of a Node.js [`Buffer`][]. The `spkac` argument can be either a string
or a [`Buffer`][].
- `spkac` {string | Buffer}
- Returns {Buffer} The challenge component of the `spkac` data structure, which
includes a public key and a challenge.
```js
const cert = require('crypto').Certificate();
@ -80,11 +78,9 @@ console.log(challenge.toString('utf8'));
<!-- YAML
added: v0.11.8
-->
The `spkac` data structure includes a public key and a challenge. The
`certificate.exportPublicKey()` returns the public key component in the
form of a Node.js [`Buffer`][]. The `spkac` argument can be either a string
or a [`Buffer`][].
- `spkac` {string | Buffer}
- Returns {Buffer} The public key component of the `spkac` data structure,
which includes a public key and a challenge.
```js
const cert = require('crypto').Certificate();
@ -98,9 +94,9 @@ console.log(publicKey);
<!-- YAML
added: v0.11.8
-->
Returns `true` if the given `spkac` data structure is valid, `false` otherwise.
The `spkac` argument must be a Node.js [`Buffer`][].
- `spkac` {Buffer}
- Returns {boolean} `true` if the given `spkac` data structure is valid, `false`
otherwise.
```js
const cert = require('crypto').Certificate();
@ -176,6 +172,7 @@ console.log(encrypted);
<!-- YAML
added: v0.1.94
-->
- `output_encoding` {string}
Returns any remaining enciphered contents. If `output_encoding`
parameter is one of `'latin1'`, `'base64'` or `'hex'`, a string is returned.
@ -189,6 +186,8 @@ once will result in an error being thrown.
<!-- YAML
added: v1.0.0
-->
- `buffer` {Buffer}
- Returns the {Cipher} for method chaining.
When using an authenticated encryption mode (only `GCM` is currently
supported), the `cipher.setAAD()` method sets the value used for the
@ -196,8 +195,6 @@ _additional authenticated data_ (AAD) input parameter.
The `cipher.setAAD()` method must be called before [`cipher.update()`][].
Returns `this` for method chaining.
### cipher.getAuthTag()
<!-- YAML
added: v1.0.0
@ -210,10 +207,12 @@ the _authentication tag_ that has been computed from the given data.
The `cipher.getAuthTag()` method should only be called after encryption has
been completed using the [`cipher.final()`][] method.
### cipher.setAutoPadding(auto_padding=true)
### cipher.setAutoPadding([auto_padding])
<!-- YAML
added: v0.7.1
-->
- `auto_padding` {boolean} Defaults to `true`.
- Returns the {Cipher} for method chaining.
When using block encryption algorithms, the `Cipher` class will automatically
add padding to the input data to the appropriate block size. To disable the
@ -227,8 +226,6 @@ using `0x0` instead of PKCS padding.
The `cipher.setAutoPadding()` method must be called before
[`cipher.final()`][].
Returns `this` for method chaining.
### cipher.update(data[, input_encoding][, output_encoding])
<!-- YAML
added: v0.1.94
@ -237,6 +234,9 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
- `output_encoding` {string}
Updates the cipher with `data`. If the `input_encoding` argument is given,
its value must be one of `'utf8'`, `'ascii'`, or `'latin1'` and the `data`
@ -322,6 +322,7 @@ console.log(decrypted);
<!-- YAML
added: v0.1.94
-->
- `output_encoding` {string}
Returns any remaining deciphered contents. If `output_encoding`
parameter is one of `'latin1'`, `'ascii'` or `'utf8'`, a string is returned.
@ -339,6 +340,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/9398
description: This method now returns a reference to `decipher`.
-->
- `buffer` {Buffer}
- Returns the {Cipher} for method chaining.
When using an authenticated encryption mode (only `GCM` is currently
supported), the `decipher.setAAD()` method sets the value used for the
@ -346,8 +349,6 @@ _additional authenticated data_ (AAD) input parameter.
The `decipher.setAAD()` method must be called before [`decipher.update()`][].
Returns `this` for method chaining.
### decipher.setAuthTag(buffer)
<!-- YAML
added: v1.0.0
@ -356,6 +357,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/9398
description: This method now returns a reference to `decipher`.
-->
- `buffer` {Buffer}
- Returns the {Cipher} for method chaining.
When using an authenticated encryption mode (only `GCM` is currently
supported), the `decipher.setAuthTag()` method is used to pass in the
@ -366,12 +369,12 @@ cipher text should be discarded due to failed authentication.
The `decipher.setAuthTag()` method must be called before
[`decipher.final()`][].
Returns `this` for method chaining.
### decipher.setAutoPadding(auto_padding=true)
### decipher.setAutoPadding([auto_padding])
<!-- YAML
added: v0.7.1
-->
- `auto_padding` {boolean} Defaults to `true`.
- Returns the {Cipher} for method chaining.
When data has been encrypted without standard block padding, calling
`decipher.setAutoPadding(false)` will disable automatic padding to prevent
@ -383,8 +386,6 @@ multiple of the ciphers block size.
The `decipher.setAutoPadding()` method must be called before
[`decipher.final()`][].
Returns `this` for method chaining.
### decipher.update(data[, input_encoding][, output_encoding])
<!-- YAML
added: v0.1.94
@ -393,6 +394,9 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
- `output_encoding` {string}
Updates the decipher with `data`. If the `input_encoding` argument is given,
its value must be one of `'latin1'`, `'base64'`, or `'hex'` and the `data`
@ -444,6 +448,9 @@ assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
<!-- YAML
added: v0.5.0
-->
- `other_public_key` {string | Buffer}
- `input_encoding` {string}
- `output_encoding` {string}
Computes the shared secret using `other_public_key` as the other
party's public key and returns the computed shared secret. The supplied
@ -459,6 +466,7 @@ If `output_encoding` is given a string is returned; otherwise, a
<!-- YAML
added: v0.5.0
-->
- `encoding` {string}
Generates private and public Diffie-Hellman key values, and returns
the public key in the specified `encoding`. This key should be
@ -470,6 +478,7 @@ or `'base64'`. If `encoding` is provided a string is returned; otherwise a
<!-- YAML
added: v0.5.0
-->
- `encoding` {string}
Returns the Diffie-Hellman generator in the specified `encoding`, which can
be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is
@ -479,6 +488,7 @@ returned; otherwise a [`Buffer`][] is returned.
<!-- YAML
added: v0.5.0
-->
- `encoding` {string}
Returns the Diffie-Hellman prime in the specified `encoding`, which can
be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is
@ -488,6 +498,7 @@ returned; otherwise a [`Buffer`][] is returned.
<!-- YAML
added: v0.5.0
-->
- `encoding` {string}
Returns the Diffie-Hellman private key in the specified `encoding`,
which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a
@ -497,6 +508,7 @@ string is returned; otherwise a [`Buffer`][] is returned.
<!-- YAML
added: v0.5.0
-->
- `encoding` {string}
Returns the Diffie-Hellman public key in the specified `encoding`, which
can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a
@ -506,6 +518,8 @@ string is returned; otherwise a [`Buffer`][] is returned.
<!-- YAML
added: v0.5.0
-->
- `private_key` {string | Buffer}
- `encoding` {string}
Sets the Diffie-Hellman private key. If the `encoding` argument is provided
and is either `'latin1'`, `'hex'`, or `'base64'`, `private_key` is expected
@ -516,6 +530,8 @@ to be a [`Buffer`][].
<!-- YAML
added: v0.5.0
-->
- `public_key` {string | Buffer}
- `encoding` {string}
Sets the Diffie-Hellman public key. If the `encoding` argument is provided
and is either `'latin1'`, `'hex'` or `'base64'`, `public_key` is expected
@ -577,6 +593,9 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `other_public_key` {string | Buffer}
- `input_encoding` {string}
- `output_encoding` {string}
Computes the shared secret using `other_public_key` as the other
party's public key and returns the computed shared secret. The supplied
@ -592,6 +611,8 @@ If `output_encoding` is given a string will be returned; otherwise a
<!-- YAML
added: v0.11.14
-->
- `encoding` {string}
- `format` {string} Defaults to `uncompressed`.
Generates private and public EC Diffie-Hellman key values, and returns
the public key in the specified `format` and `encoding`. This key should be
@ -609,15 +630,18 @@ is returned.
<!-- YAML
added: v0.11.14
-->
- `encoding` {string}
Returns the EC Diffie-Hellman private key in the specified `encoding`,
which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided
a string is returned; otherwise a [`Buffer`][] is returned.
### ecdh.getPublicKey([encoding[, format]])
### ecdh.getPublicKey([encoding][, format])
<!-- YAML
added: v0.11.14
-->
- `encoding` {string}
- `format` {string} Defaults to `uncompressed`.
Returns the EC Diffie-Hellman public key in the specified `encoding` and
`format`.
@ -634,6 +658,8 @@ returned.
<!-- YAML
added: v0.11.14
-->
- `private_key` {string | Buffer}
- `encoding` {string}
Sets the EC Diffie-Hellman private key. The `encoding` can be `'latin1'`,
`'hex'` or `'base64'`. If `encoding` is provided, `private_key` is expected
@ -650,6 +676,9 @@ deprecated: v5.2.0
> Stability: 0 - Deprecated
- `public_key` {string | Buffer}
- `encoding` {string}
Sets the EC Diffie-Hellman public key. Key encoding can be `'latin1'`,
`'hex'` or `'base64'`. If `encoding` is provided `public_key` is expected to
be a string; otherwise a [`Buffer`][] is expected.
@ -747,6 +776,7 @@ console.log(hash.digest('hex'));
<!-- YAML
added: v0.1.92
-->
- `encoding` {string}
Calculates the digest of all of the data passed to be hashed (using the
[`hash.update()`][] method). The `encoding` can be `'hex'`, `'latin1'` or
@ -764,6 +794,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
Updates the hash content with the given `data`, the encoding of which
is given in `input_encoding` and can be `'utf8'`, `'ascii'` or
@ -834,6 +866,7 @@ console.log(hmac.digest('hex'));
<!-- YAML
added: v0.1.94
-->
- `encoding` {string}
Calculates the HMAC digest of all of the data passed using [`hmac.update()`][].
The `encoding` can be `'hex'`, `'latin1'` or `'base64'`. If `encoding` is
@ -850,6 +883,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
Updates the `Hmac` content with the given `data`, the encoding of which
is given in `input_encoding` and can be `'utf8'`, `'ascii'` or
@ -929,6 +964,10 @@ console.log(sign.sign(privateKey).toString('hex'));
<!-- YAML
added: v0.1.92
-->
- `private_key` {string | Object}
- `key` {string}
- `passphrase` {string}
- `output_format` {string}
Calculates the signature on all the data passed through using either
[`sign.update()`][] or [`sign.write()`][stream-writable-write].
@ -955,6 +994,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
Updates the `Sign` content with the given `data`, the encoding of which
is given in `input_encoding` and can be `'utf8'`, `'ascii'` or
@ -1017,6 +1058,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/5522
description: The default `input_encoding` changed from `binary` to `utf8`.
-->
- `data` {string | Buffer}
- `input_encoding` {string}
Updates the `Verify` content with the given `data`, the encoding of which
is given in `input_encoding` and can be `'utf8'`, `'ascii'` or
@ -1030,10 +1073,13 @@ This can be called many times with new data as it is streamed.
<!-- YAML
added: v0.1.92
-->
- `object` {string}
- `signature` {string | Buffer}
- `signature_format` {string}
Verifies the provided data using the given `object` and `signature`.
The `object` argument is a string containing a PEM encoded object, which can be
one an RSA public key, a DSA public key, or an X.509 certificate.
an RSA public key, a DSA public key, or an X.509 certificate.
The `signature` argument is the previously calculated signature for the data, in
the `signature_format` which can be `'latin1'`, `'hex'` or `'base64'`.
If a `signature_format` is specified, the `signature` is expected to be a
@ -1084,6 +1130,8 @@ currently in use. Setting to true requires a FIPS build of Node.js.
<!-- YAML
added: v0.1.94
-->
- `algorithm` {string}
- `password` {string | Buffer}
Creates and returns a `Cipher` object that uses the given `algorithm` and
`password`.
@ -1108,6 +1156,9 @@ their own using [`crypto.pbkdf2()`][] and to use [`crypto.createCipheriv()`][]
to create the `Cipher` object.
### crypto.createCipheriv(algorithm, key, iv)
- `algorithm` {string}
- `key` {string | Buffer}
- `iv` {string | Buffer}
Creates and returns a `Cipher` object, with the given `algorithm`, `key` and
initialization vector (`iv`).
@ -1142,6 +1193,8 @@ called.
<!-- YAML
added: v0.1.94
-->
- `algorithm` {string}
- `password` {string | Buffer}
Creates and returns a `Decipher` object that uses the given `algorithm` and
`password` (key).
@ -1162,6 +1215,9 @@ to create the `Decipher` object.
<!-- YAML
added: v0.1.94
-->
- `algorithm` {string}
- `key` {string | Buffer}
- `iv` {string | Buffer}
Creates and returns a `Decipher` object that uses the given `algorithm`, `key`
and initialization vector (`iv`).
@ -1183,6 +1239,10 @@ changes:
description: The default for the encoding parameters changed
from `binary` to `utf8`.
-->
- `prime` {string | Buffer}
- `prime_encoding` {string}
- `generator` {number | string | Buffer} Defaults to `2`.
- `generator_encoding` {string}
Creates a `DiffieHellman` key exchange object using the supplied `prime` and an
optional specific `generator`.
@ -1203,6 +1263,8 @@ otherwise either a number or [`Buffer`][] is expected.
<!-- YAML
added: v0.5.0
-->
- `prime_length` {number}
- `generator` {number | string | Buffer} Defaults to `2`.
Creates a `DiffieHellman` key exchange object and generates a prime of
`prime_length` bits using an optional specific numeric `generator`.
@ -1212,6 +1274,7 @@ If `generator` is not specified, the value `2` is used.
<!-- YAML
added: v0.11.14
-->
- `curve_name` {string}
Creates an Elliptic Curve Diffie-Hellman (`ECDH`) key exchange object using a
predefined curve specified by the `curve_name` string. Use
@ -1223,6 +1286,7 @@ and description of each available elliptic curve.
<!-- YAML
added: v0.1.92
-->
- `algorithm` {string}
Creates and returns a `Hash` object that can be used to generate hash digests
using the given `algorithm`.
@ -1256,6 +1320,8 @@ input.on('readable', () => {
<!-- YAML
added: v0.1.94
-->
- `algorithm` {string}
- `key` {string | Buffer}
Creates and returns an `Hmac` object that uses the given `algorithm` and `key`.
@ -1290,6 +1356,7 @@ input.on('readable', () => {
<!-- YAML
added: v0.1.92
-->
- `algorithm` {string}
Creates and returns a `Sign` object that uses the given `algorithm`.
Use [`crypto.getHashes()`][] to obtain an array of names of the available
@ -1299,6 +1366,7 @@ signing algorithms.
<!-- YAML
added: v0.1.92
-->
- `algorithm` {string}
Creates and returns a `Verify` object that uses the given algorithm.
Use [`crypto.getHashes()`][] to obtain an array of names of the available
@ -1336,6 +1404,7 @@ console.log(curves); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]
<!-- YAML
added: v0.7.5
-->
- `group_name` {string}
Creates a predefined `DiffieHellman` key exchange object. The
supported groups are: `'modp1'`, `'modp2'`, `'modp5'` (defined in
@ -1396,6 +1465,14 @@ changes:
description: The default encoding for `password` if it is a string changed
from `binary` to `utf8`.
-->
- `password` {string}
- `salt` {string}
- `iterations` {number}
- `keylen` {number}
- `digest` {string}
- `callback` {Function}
- `err` {Error}
- `derivedKey` {Buffer}
Provides an asynchronous Password-Based Key Derivation Function 2 (PBKDF2)
implementation. A selected HMAC digest algorithm specified by `digest` is
@ -1418,9 +1495,9 @@ Example:
```js
const crypto = require('crypto');
crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, key) => {
crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, derivedKey) => {
if (err) throw err;
console.log(key.toString('hex')); // '3745e48...aa39b34'
console.log(derivedKey.toString('hex')); // '3745e48...aa39b34'
});
```
@ -1440,6 +1517,11 @@ changes:
description: The default encoding for `password` if it is a string changed
from `binary` to `utf8`.
-->
- `password` {string}
- `salt` {string}
- `iterations` {number}
- `keylen` {number}
- `digest` {string}
Provides a synchronous Password-Based Key Derivation Function 2 (PBKDF2)
implementation. A selected HMAC digest algorithm specified by `digest` is
@ -1472,95 +1554,84 @@ An array of supported digest functions can be retrieved using
<!-- YAML
added: v0.11.14
-->
- `private_key` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING`,
`RSA_PKCS1_PADDING`, or `crypto.constants.RSA_PKCS1_OAEP_PADDING`.
- `buffer` {Buffer}
Decrypts `buffer` with `private_key`.
`private_key` can be an object or a string. If `private_key` is a string, it is
treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`.
If `private_key` is an object, it is interpreted as a hash object with the
keys:
* `key`: {string} - PEM encoded private key
* `passphrase`: {string} - Optional passphrase for the private key
* `padding` : An optional padding value, one of the following:
* `crypto.constants.RSA_NO_PADDING`
* `crypto.constants.RSA_PKCS1_PADDING`
* `crypto.constants.RSA_PKCS1_OAEP_PADDING`
All paddings are defined in `crypto.constants`.
### crypto.privateEncrypt(private_key, buffer)
<!-- YAML
added: v1.1.0
-->
- `private_key` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING` or
`RSA_PKCS1_PADDING`.
- `buffer` {Buffer}
Encrypts `buffer` with `private_key`.
`private_key` can be an object or a string. If `private_key` is a string, it is
treated as the key with no passphrase and will use `RSA_PKCS1_PADDING`.
If `private_key` is an object, it is interpreted as a hash object with the
keys:
* `key`: {string} - PEM encoded private key
* `passphrase`: {string} - Optional passphrase for the private key
* `padding` : An optional padding value, one of the following:
* `crypto.constants.RSA_NO_PADDING`
* `crypto.constants.RSA_PKCS1_PADDING`
All paddings are defined in `crypto.constants`.
### crypto.publicDecrypt(public_key, buffer)
<!-- YAML
added: v1.1.0
-->
- `private_key` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING`,
`RSA_PKCS1_PADDING`, or `crypto.constants.RSA_PKCS1_OAEP_PADDING`.
- `buffer` {Buffer}
Decrypts `buffer` with `public_key`.
`public_key` can be an object or a string. If `public_key` is a string, it is
treated as the key with no passphrase and will use `RSA_PKCS1_PADDING`.
If `public_key` is an object, it is interpreted as a hash object with the
keys:
* `key`: {string} - PEM encoded public key
* `passphrase`: {string} - Optional passphrase for the private key
* `padding` : An optional padding value, one of the following:
* `crypto.constants.RSA_NO_PADDING`
* `crypto.constants.RSA_PKCS1_PADDING`
* `crypto.constants.RSA_PKCS1_OAEP_PADDING`
Because RSA public keys can be derived from private keys, a private key may
be passed instead of a public key.
All paddings are defined in `crypto.constants`.
### crypto.publicEncrypt(public_key, buffer)
<!-- YAML
added: v0.11.14
-->
- `private_key` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING`,
`RSA_PKCS1_PADDING`, or `crypto.constants.RSA_PKCS1_OAEP_PADDING`.
- `buffer` {Buffer}
Encrypts `buffer` with `public_key`.
`public_key` can be an object or a string. If `public_key` is a string, it is
treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`.
If `public_key` is an object, it is interpreted as a hash object with the
keys:
* `key`: {string} - PEM encoded public key
* `passphrase`: {string} - Optional passphrase for the private key
* `padding` : An optional padding value, one of the following:
* `crypto.constants.RSA_NO_PADDING`
* `crypto.constants.RSA_PKCS1_PADDING`
* `crypto.constants.RSA_PKCS1_OAEP_PADDING`
Because RSA public keys can be derived from private keys, a private key may
be passed instead of a public key.
All paddings are defined in `crypto.constants`.
### crypto.randomBytes(size[, callback])
<!-- YAML
added: v0.5.8
-->
- `size` {number}
- `callback` {Function}
- `err` {Error}
- `buf` {Buffer}
Generates cryptographically strong pseudo-random data. The `size` argument
is a number indicating the number of bytes to generate.
@ -1599,6 +1670,8 @@ time is right after boot, when the whole system is still low on entropy.
<!-- YAML
added: v0.11.11
-->
- `engine` {string}
- `flags` {crypto.constants} Defaults to `crypto.constants.ENGINE_METHOD_ALL`.
Load and set the `engine` for some or all OpenSSL functions (selected by flags).
@ -1626,6 +1699,8 @@ is a bit field taking one of or a mix of the following flags (defined in
<!-- YAML
added: v6.6.0
-->
- `a` {Buffer}
- `b` {Buffer}
Returns true if `a` is equal to `b`, without leaking timing information that
would allow an attacker to guess one of the values. This is suitable for

Loading…
Cancel
Save