diff --git a/README.md b/README.md
index ec351703..d485e3c1 100644
--- a/README.md
+++ b/README.md
@@ -80,9 +80,12 @@ $ npm install @types/node
## Upgrading
-This library follows `semver`. As such, major version bumps usually mean API changes or behavior changes. Please check [upgrade notes](https://github.com/yeojz/otplib/wiki/upgrade-notes) for more information, especially before making any major upgrades.
+This library follows `semver`. As such, major version bumps usually mean API changes or behavior changes.
+Please check [upgrade notes](https://github.com/yeojz/otplib/wiki/upgrade-notes) for more information,
+especially before making any major upgrades.
-You might also want to check out the release notes associated with each tagged versions in the [releases](https://github.com/yeojz/otplib/releases) page.
+You might also want to check out the release notes associated with each tagged versions
+in the [releases](https://github.com/yeojz/otplib/releases) page.
## Getting Started
@@ -112,7 +115,7 @@ import totp from 'otplib/totp';
import authenticator from 'otplib/authenticator';
```
-**Note**: If you import the libraries directly, you'll have to provide a crypto
+**Note**: If you import the libraries directly, you will have to provide a crypto
solution (this is to allow custom crypto solutions), as long as they implement `createHmac` and `randomBytes`.
Take a look at the [browser implementation](https://github.com/yeojz/otplib/blob/master/packages/otplib-browser)
of this package as an example.
@@ -148,6 +151,12 @@ const TOTP = totp.TOTP;
import authenticator from 'otplib/authenticator';
const Authenticator = authenticator.Authenticator;
// const inst = new Authenticator();
+
+// Alternatively, you can get it from the default module as well
+import otplib from 'otplib';
+const HOTP = otplib.hotp.HOTP
+const TOTP = otplib.totp.TOTP
+const Authenticator = otplib.authenticator.Authenticator
```
**Example Usage**
@@ -227,12 +236,15 @@ Ihis library been split and classified into 6 core files with other specific env
### Other Bundles
-| file | description |
-| ---------------------------------------------------------------------------------------- | --------------------------------------------- |
-| [otplib-browser.js](https://yeojz.github.io/otplib/docs/module-otplib-browser.html.html) | Browser compatible package built with webpack |
+| file | description |
+| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [otplib-browser.js](https://yeojz.github.io/otplib/docs/module-otplib-browser.html) | Browser compatible package built with webpack |
+| [otplib-expo.js](https://yeojz.github.io/otplib/docs/module-otplib-expo.html) (alpha) | Package modified for `expo.io`, built with webpack ([read more](https://github.com/yeojz/otplib/pull/18)).
_Note_: I have **not** personally tested the `otplib-expo` module.
If the main library works in newer expo releases, I would recommend that. |
For more information about the functions, check out the [documentation][project-docs].
+
+
## Notes
### Setting Custom Options
@@ -262,22 +274,16 @@ otplib.authenticator.resetOptions();
#### Available Options
-| Option | Type | Defaults | Description |
-| ---------------- | ---------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| algorithm | string | 'sha1' | Algorithm used for HMAC |
-| createHmacSecret | function | hotpSecret, totpSecret | Transforms the secret and applies any modifications like padding to it. |
-| crypto | object | node crypto | Crypto module to use. |
-| digits | integer | 6 | The length of the token |
-| encoding | string | 'ascii' ('hex' for Authenticator) | The encoding of secret which is given to digest |
-| epoch (totp) | integer | null | Starting time since the UNIX epoch (seconds). |
-| step (totp) | integer | 30 | Time step (seconds) |
-| window (totp) | integer or array | 0 | Tokens in the previous and future x-windows that should be considered valid. If integer, same value will be used for both. Alternatively, define array: `[previous, future]` |
-
-_Note 1_: epoch format is non-javascript. i.e. `Date.now() / 1000`
-
-_Note 2_: non "totp" label applies to all
-
-_Note 3_: "totp" applies to authenticator as well
+| Option | Type | Defaults | Description |
+| ---------------------------- | ---------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| algorithm | string | 'sha1' | Algorithm used for HMAC |
+| createHmacSecret | function | hotpSecret, totpSecret | Transforms the secret and applies any modifications like padding to it. |
+| crypto | object | node crypto | Crypto module to use. |
+| digits | integer | 6 | The length of the token |
+| encoding | string | 'ascii' ('hex' for authenticator) | The encoding of secret which is given to digest |
+| epoch (totp, authenticator) | integer | null | Starting time since the UNIX epoch (seconds).
epoch format is non-javascript. i.e. `Date.now() / 1000` |
+| step (totp, authenticator) | integer | 30 | Time step (seconds) |
+| window (totp, authenticator) | integer or array | 0 | Tokens in the previous and future x-windows that should be considered valid.
If integer, same value will be used for both.
Alternatively, define array: `[previous, future]` |
### Seed / secret length
@@ -289,7 +295,7 @@ HMAC-SHA256 - 32 bytes
HMAC-SHA512 - 64 bytes
```
-As such, the length of the secret is padded and sliced according to the expected length for respective algrorithms.
+As such, the length of the secret is padded and sliced according to the expected length for respective algorithms.
### Google Authenticator
@@ -302,7 +308,8 @@ The default encoding option has been set to `hex` (Authenticator) instead of `as
Google Authenticator requires keys to be base32 encoded.
It also requires the base32 encoder to be [RFC 3548][rfc-3548] compliant.
-OTP calculation will still work should you want to use other base32 encoding methods (like Crockford's Base 32) but it will NOT be compatible with Google Authenticator.
+OTP calculation will still work should you want to use other base32 encoding methods (like Crockford's Base 32)
+but it will NOT be compatible with Google Authenticator.
```js
import authenticator from 'otplib/authenticator';
diff --git a/build.config.js b/build.config.js
index 73eb3e14..07e1919b 100644
--- a/build.config.js
+++ b/build.config.js
@@ -4,6 +4,12 @@ const browsers = {
}
};
+const nodejs = {
+ targets: {
+ node: '6'
+ }
+};
+
module.exports = {
otplib: {
bundler: 'rollup',
@@ -42,5 +48,11 @@ module.exports = {
babel: {
presets: [['env', browsers]]
}
+ },
+ 'otplib-expo': {
+ bundler: 'webpack',
+ babel: {
+ presets: [['env', nodejs]]
+ }
}
};
diff --git a/packages/otplib-browser/randomBytes.js b/packages/otplib-browser/randomBytes.js
index 91675b65..71c01d36 100644
--- a/packages/otplib-browser/randomBytes.js
+++ b/packages/otplib-browser/randomBytes.js
@@ -7,7 +7,7 @@
*
* @module otplib-browser/randomBytes
* @param {string} size - the size
- * @return {string}
+ * @return {Buffer}
*/
function randomBytes(size) {
const crypto = window.crypto || window.msCrypto;
diff --git a/packages/otplib-expo/crypto.js b/packages/otplib-expo/crypto.js
new file mode 100644
index 00000000..00badbfd
--- /dev/null
+++ b/packages/otplib-expo/crypto.js
@@ -0,0 +1,12 @@
+import crypto from 'crypto';
+import randomBytes from './randomBytes';
+
+/**
+ * Crypto replacement for expo
+ *
+ * @module otplib-expo/crypto
+ */
+export default {
+ createHmac: crypto.createHmac,
+ randomBytes
+};
diff --git a/packages/otplib-expo/crypto.spec.js b/packages/otplib-expo/crypto.spec.js
new file mode 100644
index 00000000..8a69e541
--- /dev/null
+++ b/packages/otplib-expo/crypto.spec.js
@@ -0,0 +1,9 @@
+import crypto from './crypto';
+
+describe('crypto', () => {
+ it('should expose an object with a used method', () => {
+ expect(typeof crypto).toBe('object');
+ expect(typeof crypto.createHmac).toBe('function');
+ expect(typeof crypto.randomBytes).toBe('function');
+ });
+});
diff --git a/packages/otplib-expo/index.js b/packages/otplib-expo/index.js
new file mode 100644
index 00000000..f5606888
--- /dev/null
+++ b/packages/otplib-expo/index.js
@@ -0,0 +1,22 @@
+import hotp from 'otplib-hotp';
+import totp from 'otplib-totp';
+import authenticator from 'otplib-authenticator';
+import crypto from './crypto';
+
+/**
+ * otplib-expo
+ *
+ * One-Time Password Library for use with https://expo.io
+ *
+ * @module otplib-expo
+ * @since 10.0.0
+ */
+authenticator.options = { crypto };
+hotp.options = { crypto };
+totp.options = { crypto };
+
+module.exports = {
+ authenticator,
+ hotp,
+ totp
+};
diff --git a/packages/otplib-expo/randomBytes.js b/packages/otplib-expo/randomBytes.js
new file mode 100644
index 00000000..3db0b8dc
--- /dev/null
+++ b/packages/otplib-expo/randomBytes.js
@@ -0,0 +1,31 @@
+/**
+ * randomBytes naive implementation.
+ *
+ * Required for expo applications that don't offer a native
+ * secure random implementaton
+ *
+ * @module otplib-expo/randomBytes
+ * @param {string} size - the size
+ * @return {Buffer}
+ */
+function randomBytes(size) {
+ if (size > 65536) {
+ throw new Error('Requested size of random bytes is too large');
+ }
+
+ if (size < 1) {
+ throw new Error('Requested size must be more than 0');
+ }
+
+ const rawBytes = new Uint8Array(size).map(() => randomUint8());
+
+ return new Buffer(rawBytes.buffer);
+}
+
+function randomUint8() {
+ const low = 0;
+ const high = 255;
+ return Math.floor(Math.random() * (high - low + 1) + low);
+}
+
+export default randomBytes;
diff --git a/packages/otplib-expo/randomBytes.spec.js b/packages/otplib-expo/randomBytes.spec.js
new file mode 100644
index 00000000..91ad3b38
--- /dev/null
+++ b/packages/otplib-expo/randomBytes.spec.js
@@ -0,0 +1,20 @@
+import randomBytes from './randomBytes';
+
+describe('randomBytes', () => {
+ const tooLarge = 'Requested size of random bytes is too large';
+ const wrongSize = 'Requested size must be more than 0';
+
+ it('should return a buffer', () => {
+ const result = randomBytes(10);
+ expect(result).toBeInstanceOf(Buffer);
+ expect(result).toHaveLength(10);
+ });
+
+ it('should throw when size is too big', () => {
+ expect(() => randomBytes(65537)).toThrowError(tooLarge);
+ });
+
+ it('should throw when size is < 1', () => {
+ expect(() => randomBytes(0)).toThrowError(wrongSize);
+ });
+});