nestjs-cryptography 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/SECURITY.md +14 -0
  2. package/dist/constants.d.ts +15 -0
  3. package/dist/constants.js +16 -1
  4. package/dist/cryptography.service.d.ts +3 -2
  5. package/dist/cryptography.service.js +101 -21
  6. package/dist/interfaces/cryptography-options.interface.d.ts +20 -16
  7. package/package.json +23 -16
  8. package/wiki/README.md +0 -41
  9. package/wiki/babel.config.js +0 -3
  10. package/wiki/docs/Internals/_category_.json +0 -7
  11. package/wiki/docs/Internals/create-safe-random-data.mdx +0 -41
  12. package/wiki/docs/Internals/create-secure-hmac.mdx +0 -31
  13. package/wiki/docs/Internals/symmetric-data-encrypt.mdx +0 -103
  14. package/wiki/docs/Internals/symmetric-secure-data-encrypt.mdx +0 -161
  15. package/wiki/docs/api-reference/_category_.json +0 -7
  16. package/wiki/docs/api-reference/settings.mdx +0 -199
  17. package/wiki/docs/guides/_category_.json +0 -7
  18. package/wiki/docs/guides/generics.mdx +0 -170
  19. package/wiki/docs/guides/hashing.mdx +0 -258
  20. package/wiki/docs/guides/hmac.mdx +0 -271
  21. package/wiki/docs/guides/key-derivation.mdx +0 -101
  22. package/wiki/docs/guides/password-hashing.mdx +0 -136
  23. package/wiki/docs/guides/symmetric-encryption.mdx +0 -272
  24. package/wiki/docs/intro.mdx +0 -148
  25. package/wiki/docusaurus.config.ts +0 -138
  26. package/wiki/package.json +0 -48
  27. package/wiki/sidebars.ts +0 -20
  28. package/wiki/src/common/timing-attack.mdx +0 -3
  29. package/wiki/src/common/tips.mdx +0 -18
  30. package/wiki/src/components/GenerateHexButton/index.tsx +0 -35
  31. package/wiki/src/components/GenerateHexButton/styles.module.css +0 -10
  32. package/wiki/src/components/GenericLabel/index.tsx +0 -19
  33. package/wiki/src/components/HomepageFeatures/index.tsx +0 -70
  34. package/wiki/src/components/HomepageFeatures/styles.module.css +0 -11
  35. package/wiki/src/components/RecommendedLabel/index.tsx +0 -19
  36. package/wiki/src/components/RequiredLabel/index.tsx +0 -12
  37. package/wiki/src/css/custom.css +0 -30
  38. package/wiki/src/pages/index.module.css +0 -23
  39. package/wiki/src/pages/index.tsx +0 -43
  40. package/wiki/src/pages/markdown-page.md +0 -7
  41. package/wiki/static/.nojekyll +0 -0
  42. package/wiki/static/img/gear_api.png +0 -0
  43. package/wiki/static/img/logo.svg +0 -1
  44. package/wiki/static/img/nestjs_favicon.ico +0 -0
  45. package/wiki/static/img/node_crypto.png +0 -0
  46. package/wiki/static/img/phc_logo.png +0 -0
  47. package/wiki/static/img/profile.png +0 -0
  48. package/wiki/versioned_docs/version-2.x/Internals/_category_.json +0 -8
  49. package/wiki/versioned_docs/version-2.x/Internals/create-secure-hmac.mdx +0 -30
  50. package/wiki/versioned_docs/version-2.x/Internals/symmetric-secure-data-encrypt.mdx +0 -160
  51. package/wiki/versioned_docs/version-2.x/api-reference/_category_.json +0 -8
  52. package/wiki/versioned_docs/version-2.x/api-reference/settings.mdx +0 -197
  53. package/wiki/versioned_docs/version-2.x/guides/_category_.json +0 -7
  54. package/wiki/versioned_docs/version-2.x/guides/generics.mdx +0 -133
  55. package/wiki/versioned_docs/version-2.x/guides/hashing.mdx +0 -229
  56. package/wiki/versioned_docs/version-2.x/guides/hmac.mdx +0 -198
  57. package/wiki/versioned_docs/version-2.x/guides/key-derivation.mdx +0 -98
  58. package/wiki/versioned_docs/version-2.x/guides/password-hashing.mdx +0 -132
  59. package/wiki/versioned_docs/version-2.x/guides/symmetric-encryption.mdx +0 -107
  60. package/wiki/versioned_docs/version-2.x/intro.mdx +0 -148
  61. package/wiki/versioned_sidebars/version-2.x-sidebars.json +0 -8
  62. package/wiki/versions.json +0 -3
@@ -1,161 +0,0 @@
1
- ---
2
- title: Symmetric Secure Data Encrypt
3
- sidebar_label: Symmetric Secure Data Encrypt
4
- sidebar_position: 3
5
- description: Internals of symmetricSecureDataEncrypt
6
- ---
7
-
8
- In the following section, you will see a diagram of the cryptographic operations performed when calling the method [`symmetricSecureDataEncrypt`][1]
9
-
10
- This method securely encrypts input data by first generating a random 32-byte Data Encryption Key (DEK)
11
- using a cryptographically secure method. It then encrypts the data using AES-256-GCM with the DEK,
12
- producing an output that includes the initialization vector (IV), salt, authentication tag, and ciphertext.
13
- After encrypting the data, the method also encrypts the DEK itself using a master key, and finally,
14
- it concatenates the encrypted DEK and the encrypted data, returning the complete encrypted result for secure storage or transmission.
15
-
16
- ## **Diagram**
17
-
18
- <div style={{ textAlign: 'center' }}>
19
- ```mermaid
20
- graph TD
21
- A[Input: Data] --> ID
22
-
23
- DEK{Generate DEK} --> SG1
24
-
25
- subgraph SG1[Generate DEK]
26
- SG1A1[Generate 64 bytes of random data] --> SG1A1A2[Create Secret Key from random data]
27
- SG1A1A2 --> SG1A1A3[Generate another 64 bytes of random data]
28
- SG1A1A3 --> SG1A1A4[Use HKDF with sha3-256 to derive IV]
29
- end
30
-
31
-
32
- subgraph ED[Encrypt Data]
33
- SG1A1A4 --> DEK1[DEK]
34
-
35
- ID(DATA)
36
-
37
- IV1[IV] --> IV1A1{Generate IV}
38
- SALT1[SALT] --> SALT1A1{Generate SALT}
39
-
40
- IV1A1 --> SGIV1
41
- SALT1A1 --> SGSALT1
42
-
43
- subgraph SGIV1["Generate IV (12 bytes)"]
44
- SGIV1A1[Generate 64 bytes of random data] --> SGIV1A1A2[Create Secret Key from random data]
45
- SGIV1A1A2 --> SGIV1A1A3[Generate another 64 bytes of random data]
46
- SGIV1A1A3 --> SGIV1A1A4[Use HKDF with sha3-256 to derive IV]
47
- end
48
-
49
- subgraph SGSALT1["Generate Salt (64 bytes)"]
50
- SGSSALT1A1[Generate 64 bytes of random data] --> SGSSALT1A1A2[Create Secret Key from random data]
51
- SGSSALT1A1A2 --> SGSSALT1A1A3[Generate another 64 bytes of random data]
52
- SGSSALT1A1A3 --> SGSSALT1A1A4[Use HKDF with sha3-256 to derive SALT]
53
- end
54
-
55
- DEK1 --> DERIVEDEK[Securely derive DEK using Argon2 + Salt]
56
- DERIVEDEK --> EK1(Encryption Key)
57
- SGSSALT1A1A4 --> DERIVEDEK
58
-
59
- SGIV1A1A4 --> FIV1(IV)
60
- FIV1 ==> FED{Encrypt Data using AES-256-GCM with Encryption Key + IV}
61
- EK1 ==> FED
62
- ID ==> FED
63
-
64
- FED -.- FFED["Encrypted Data [IV + Salt + AuthTag + CipherText]"]
65
- end
66
-
67
-
68
- subgraph EDEK[Encrypt DEK]
69
- SG1A1A4 --> DEK2(DEK)
70
-
71
- IV2[IV] --> IV2A1{Generate IV}
72
- SALT2[SALT] --> SALT2A1{Generate SALT}
73
-
74
- IV2A1 --> SGIV2
75
- SALT2A1 --> SGSALT2
76
-
77
- subgraph SGIV2["Generate IV (12 bytes)"]
78
- SGIV2A1[Generate 64 bytes of random data] --> SGIV2A1A2[Create Secret Key from random data]
79
- SGIV2A1A2 --> SGIV2A1A3[Generate another 64 bytes of random data]
80
- SGIV2A1A3 --> SGIV2A1A4[Use HKDF with sha3-256 to derive IV]
81
- end
82
-
83
- subgraph SGSALT2["Generate Salt (64 bytes)"]
84
- SGSSALT2A1[Generate 64 bytes of random data] --> SGSSALT2A1A2[Create Secret Key from random data]
85
- SGSSALT2A1A2 --> SGSSALT2A1A3[Generate another 64 bytes of random data]
86
- SGSSALT2A1A3 --> SGSSALT2A1A4[Use HKDF with sha3-256 to derive SALT]
87
- end
88
-
89
- MK[MASTER KEY] --> DERIVEMK[Securely derive Master Key using Argon2 + Salt]
90
- DERIVEMK --> EK2(Encryption Key)
91
- SGSSALT2A1A4 --> DERIVEMK
92
-
93
- SGIV2A1A4 --> FIV2(IV)
94
-
95
- EK2 ==> FEDEK{Encrypt DEK using AES-256-GCM with Encryption Key + IV}
96
- DEK2 ==> FEDEK
97
- FIV2 ==> FEDEK
98
-
99
- FEDEK -.- FFEDEK["Encrypted DEK [IV + Salt + AuthTag + CipherText]"]
100
- end
101
-
102
- FFEDEK -.-> FFDD(["Concatenate Encrypted DEK + Encrypted Data"])
103
- FFED -.-> FFDD
104
-
105
-
106
- %% -----------------
107
-
108
- A:::inputDataStyle
109
-
110
- MK:::masterKeyStyle
111
-
112
- DEK:::dekStyle
113
-
114
- SALT1A1:::saltStyle
115
- SALT2A1:::saltStyle
116
-
117
- IV1A1:::ivStyle
118
- IV2A1:::ivStyle
119
-
120
- FEDEK:::encryptionStyle
121
- FED:::encryptionStyle
122
-
123
- FFEDEK:::resultStyle
124
- FFED:::resultStyle
125
-
126
- FFDD:::finalResultStyle
127
-
128
- %% Style definitions
129
- classDef inputDataStyle fill:#00ff00,stroke:#333,stroke-width:2px;
130
- classDef masterKeyStyle fill:#ff0000,stroke:#333,stroke-width:2px;
131
- classDef dekStyle fill:#BCD3A3,stroke:#333,stroke-width:2px;
132
- classDef ivStyle fill:#ffcc00,stroke:#333,stroke-width:2px;
133
- classDef saltStyle fill:#ff6666,stroke:#333,stroke-width:2px;
134
- classDef deriveKeyStyle fill:#66ccff,stroke:#333,stroke-width:2px;
135
- classDef secureKeyStyle fill:#66ff66,stroke:#333,stroke-width:2px;
136
- classDef encryptionStyle fill:#cc99ff,stroke:#333,stroke-width:2px;
137
- classDef resultStyle fill:#ff9966,stroke:#333,stroke-width:2px;
138
- classDef finalResultStyle fill:#66ffcc,stroke:#333,stroke-width:2px;
139
- ```
140
- </div>
141
-
142
-
143
- ## **Explanation of the Diagram**
144
- 1) Generate DEK:
145
- - The `createSafeRandomData` method generates a 32-byte **DEK** (Data Encryption Key) using `HKDF(sha3-256 + random_key + random_salt)`.
146
- 2) Encrypt the Input Data:
147
- - **Generate IV (12 bytes)**: A 12-byte IV is generated using `HKDF(sha3-256 + random_key + random_salt)`.
148
- - **Generate Salt (64 bytes)**: A 64-byte salt is generated, also using `HKDF(sha3-256 + random_key + random_salt)`.
149
- - **Derive Secure Encryption Key**: A secure encryption key is derived using **Argon2** with the DEK and salt.
150
- - **Encrypt Data**: The input data is encrypted using **AES-256-GCM** with the derived secure encryption key, producing the encrypted result: _IV + Salt + AuthTag + CipherText_.
151
- 3) Encrypt the DEK:
152
- - The DEK itself is encrypted using the master key:
153
- - **Generate IV (12 bytes)**: A 12-byte IV is generated using `HKDF(sha3-256 + random_key + random_salt)`.
154
- - **Generate Salt (64 bytes)**: A 64-byte salt is generated, also using `HKDF(sha3-256 + random_key + random_salt)`.
155
- - **Derive Master Key**: A secure encryption key is derived using **Argon2** with the [**MasterKey**][2] and salt.
156
- - **Encrypt DEK**: The DEK is encrypted using AES-256-GCM, resulting in the encrypted DEK: _IV + Salt + AuthTag + CipherText_.
157
- 4) Concatenate and Return:
158
- - The encrypted DEK and the encrypted input data are concatenated to form the final output, which is then returned.
159
-
160
- [1]: ../guides/symmetric-encryption#symmetricsecuredataencrypt
161
- [2]: ../api-reference/settings#masterkey-1
@@ -1,7 +0,0 @@
1
- {
2
- "label": "API Reference",
3
- "position": 2,
4
- "link": {
5
- "type": "generated-index",
6
- }
7
- }
@@ -1,199 +0,0 @@
1
- ---
2
- title: Configuration Options
3
- sidebar_label: Configuration Options
4
- sidebar_position: 1
5
- description: Module configuration options
6
-
7
- ---
8
-
9
- import Tabs from '@theme/Tabs';
10
- import TabItem from '@theme/TabItem';
11
- import GenerateHexButton from '@site/src/components/GenerateHexButton';
12
-
13
- <details>
14
- <summary>👨‍🔧 Let me help you a bit....</summary>
15
-
16
- <div>
17
-
18
- :::info
19
-
20
- If at any point you need to securely generate a secret key for the following configuration, you can do so as follows.
21
-
22
- <Tabs
23
- defaultValue="linux"
24
- values={[
25
- { label: 'Linux / macOS', value: 'linux', },
26
- { label: 'Windows / Others', value: 'windows', }
27
- ]
28
- }>
29
- <TabItem value="linux">
30
- Type this on the terminal:
31
- ```bash
32
- openssl rand -hex 32
33
- ```
34
- </TabItem>
35
- <TabItem value="windows">
36
- <GenerateHexButton />
37
- </TabItem>
38
- </Tabs>
39
-
40
-
41
- :::
42
-
43
- </div>
44
- </details>
45
-
46
- <details>
47
- <summary>Example Usage</summary>
48
-
49
- <div>
50
-
51
- ```typescript title="app.module.ts"
52
- import { Module } from '@nestjs/common';
53
- import * as argon2 from 'argon2';
54
- import {
55
- CryptographyModule,
56
- CryptographyOptionsInterface,
57
- } from 'nestjs-cryptography';
58
-
59
- @Module({
60
- imports: [
61
- CryptographyModule.registerAsync({
62
- imports: [ConfigModule],
63
- isGlobal: true,
64
- useFactory: (configService: ConfigService) =>
65
- ({
66
- isGlobal: true,
67
- kdf: {
68
- timeCost: 32,
69
- memoryCost: 131072,
70
- argon2Type: argon2.argon2i,
71
- outputKeyLength: 32,
72
- },
73
- hashing: {
74
- password: {
75
- timeCost: 10,
76
- memoryCost: 65536,
77
- argon2Type: argon2.argon2id,
78
- outputKeyLength: 64,
79
- },
80
- hmac: {
81
- // ‼️ change me please ‼️
82
- masterKey: '6c0504d3836ab96a25daeb61c44f6d6345d99a746f6a776290c48d9a5ba8b124',
83
- },
84
- },
85
- encryption: {
86
- symmetric: {
87
- // ‼️ change me please ‼️
88
- masterKey: '1538755db39d3d98115af5be688b1486673910f7d2630fc48dd27c1a1ace2631',
89
- },
90
- },
91
- }) as CryptographyOptionsInterface,
92
- inject: [ConfigService],
93
- }),
94
- ],
95
- export class AppModule {}
96
- ```
97
-
98
- </div>
99
- </details>
100
-
101
- ## `kdf`
102
-
103
- Settings for the Key Derivation Function.
104
-
105
- - ### <u>outputKeyLength</u>
106
- > `type: number` | **required**
107
-
108
- The default length (in bytes) of the derived key.
109
-
110
- - ### <u>argon2Type</u>
111
- > `type: Argon2Type` | **required**
112
-
113
- The variant of the Argon2 algorithm to use (Argon2d, Argon2i, or Argon2id)
114
-
115
- - ### <u>memoryCost</u>
116
- > `type: number` | **required**
117
-
118
- Memory usage (in kilobytes) for the algorithm.
119
-
120
- - ### <u>timeCost</u>
121
- > `type: number` | **required**
122
-
123
- Number of iterations to perform.
124
-
125
- ---
126
-
127
- ## `hashing`
128
-
129
- Settings for hashing operations.
130
-
131
- ### `password`
132
-
133
- Configuration for password hashing.
134
-
135
- - ### <u>outputKeyLength</u>
136
- > `type: number` | **required**
137
-
138
- The default length (in bytes) of the derived key.
139
-
140
- - ### <u>argon2Type</u>
141
- > `type: Argon2Type` | **required**
142
-
143
- The variant of the Argon2 algorithm to use (Argon2d, Argon2i, or Argon2id)
144
-
145
- - ### <u>memoryCost</u>
146
- > `type: number` | **required**
147
-
148
- Memory usage (in kilobytes) for the algorithm.
149
-
150
- - ### <u>timeCost</u>
151
- > `type: number` | **required**
152
-
153
- Number of iterations to perform.
154
-
155
- ### `hmac`
156
-
157
- Configuration for HMAC (Hash-Based Message Authentication Code).
158
-
159
- - ### <u>masterKey</u>
160
- > `type: string` | **required**
161
-
162
- The secret key used for generating HMACs.
163
-
164
- ---
165
-
166
- ## `encryption`
167
-
168
- Settings for encryption operations.
169
-
170
- ### `symmetric`
171
-
172
- Configuration for symmetric encryption.
173
-
174
- - ### <u>masterKey</u>
175
- > `type: string` | **required**
176
-
177
- The secret key used for encryption and decryption.
178
-
179
- :::danger
180
-
181
- Note: Always ensure that secret keys are generated securely and stored safely.
182
- Do not hard-code them into your source files or expose them in version control systems.
183
-
184
- :::
185
-
186
- ## Additional Information
187
-
188
- - **Argon2Type**: An enumeration defining the type of Argon2 algorithm to use.
189
- The options typically include `Argon2d`, `Argon2i`, and `Argon2id`.
190
- [Choose the one that best fits your security requirements][3].
191
-
192
- - **Security Considerations**: Adjust `memoryCost` and `timeCost`
193
- according to the desired balance between performance and security.
194
- Higher values increase security but require more resources.
195
- You could se more information on [owasp][1] or the [official specs][2]
196
-
197
- [1]: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
198
- [2]: https://www.password-hashing.net/argon2-specs.pdf#page=15
199
- [3]: https://en.wikipedia.org/wiki/Argon2
@@ -1,7 +0,0 @@
1
- {
2
- "label": "Guides",
3
- "position": 3,
4
- "link": {
5
- "type": "generated-index"
6
- }
7
- }
@@ -1,170 +0,0 @@
1
- ---
2
- title: Generics
3
- sidebar_label: Generics
4
- sidebar_position: 1
5
- description: Methods to perform typical operations UUID, randomPassword, ...
6
- ---
7
-
8
- import RequiredLabel from '@site/src/components/RequiredLabel';
9
- import Tips from '@site/src/common/tips.mdx'
10
-
11
- This section contains some generic methods to perform typical operations
12
-
13
- ## Generate an UUIDv4
14
-
15
- Method to generate a UUID version 4.
16
-
17
- ### `genUUID`
18
-
19
- ```tsx
20
- public genUUID (
21
- secure = false
22
- ): string;
23
- ```
24
-
25
- **Parameters:**
26
-
27
- | Name | Type | Default | Description |
28
- |--------|---------|---------|--------------------------------------------------------------------------------|
29
- | secure | boolean | false | Decide to use a more secure generation, preventing the use of an entropy cache |
30
-
31
-
32
- **Outputs:**
33
-
34
- As output, it will return a string of this format `0E928AD4-4D11-4C7C-A83A-8DD7361FFC01`
35
-
36
-
37
- **Usage:**
38
- ```typescript
39
- async someAwesomeMethod(): Promise<string> {
40
- const newUUID = this.cryptographyService.genUUID(true);
41
- ...
42
- return newUUID;
43
- }
44
- ```
45
-
46
-
47
- [//]: #--------------------#
48
-
49
- ## Generate secure random data
50
-
51
- Method to generate a secure random data of the desired length.
52
-
53
- ### `createSafeRandomData`
54
-
55
- ```tsx
56
- public createSafeRandomData (
57
- length: number
58
- ): Buffer;
59
- ```
60
-
61
- **Parameters:**
62
-
63
- | Name | Type | Default | Description |
64
- |-------------------------|--------|---------|----------------------------------------|
65
- | length <RequiredLabel/> | number | | The random data output length in bytes |
66
-
67
-
68
- **Outputs:**
69
-
70
- As output, it will return a [Buffer][1] `<Buffer cc 2b.....cd a1 08>`
71
-
72
-
73
- [//]: #--------------------#
74
-
75
-
76
- ## Generate random password
77
-
78
- Method to generate a random password with this set of characters: `A-Z a-z 0-9 + = /`.
79
-
80
- ### `genRandomPassword`
81
-
82
- ```tsx
83
- public genRandomPassword (
84
- length: number
85
- ): string;
86
- ```
87
-
88
- **Parameters:**
89
-
90
- | Name | Type | Default | Description |
91
- |---------------------------|---------------|---------|--------------------------------------------------|
92
- | length <RequiredLabel/> | number | | The password output length |
93
-
94
-
95
- **Outputs:**
96
-
97
- As output, it will return a string of this format: `jh2EducrV7yH8tGAc8Jkdcso`
98
-
99
- **Usage:**
100
- ```typescript
101
- async createUserPassword(): Promise<string> {
102
- const newPassword = this.cryptographyService.genRandomPassword(24);
103
- ...
104
- return newPassword;
105
- }
106
- ```
107
-
108
-
109
- [//]: #--------------------#
110
-
111
-
112
- ## Generate symmetric key
113
-
114
- Method to generate a cryptographically secure SymmetricKey in [KeyObject][1] format
115
- to use in subsequent encryption/decryption operations.
116
-
117
- ### `generateSymmetricKey`
118
-
119
- ```tsx
120
- public generateSymmetricKey (
121
- length: number = 256
122
- ): KeyObject;
123
- ```
124
-
125
- **Parameters:**
126
-
127
- | Name | Type | Default | Description |
128
- |--------|--------|---------|---------------------------------|
129
- | length | number | 256 | The symmetric key output length |
130
-
131
-
132
- **Outputs:**
133
-
134
- As output, it will return an object of type [KeyObject][1].
135
-
136
- :::info
137
-
138
- If you want to export this KeyObject to different types, you can access the [`.export` method.][2]
139
-
140
- :::
141
-
142
- **Usage:**
143
- ```typescript
144
- async createSymmetricKey(): Promise<void> {
145
- const new32KeySize = this.cryptographyService.generateSymmetricKey(32);
146
- console.log(new32KeySize.export().toString('hex')); // f32.....4ee
147
-
148
- const aes128KeySize = this.cryptographyService.generateSymmetricKey(128);
149
- console.log(aes128KeySize.export().toString('hex')); // e89.....41e
150
-
151
- const aes192KeySize = this.cryptographyService.generateSymmetricKey(192);
152
- console.log(aes192KeySize.export().toString('base64')); // 8OI.....ZQ=
153
-
154
- const aes256KeySize = this.cryptographyService.generateSymmetricKey(256);
155
- console.log(aes256KeySize.export()); // <Buffer cc 2b.....cd a1 08>
156
- }
157
- ```
158
-
159
-
160
- [//]: #--------------------#
161
-
162
-
163
- <Tips />
164
-
165
-
166
- [//]: #--------------------#
167
-
168
-
169
- [1]: https://nodejs.org/api/crypto.html#class-keyobject
170
- [2]: https://nodejs.org/api/crypto.html#keyobjectexportoptions