Skip to content

Commit

Permalink
feat: add support for expo.io
Browse files Browse the repository at this point in the history
  • Loading branch information
yeojz committed Jun 15, 2018
1 parent b5fe7ca commit e17b21b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 25 deletions.
55 changes: 31 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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**
Expand Down Expand Up @@ -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)). <br /> _Note_: I have **not** personally tested the `otplib-expo` module. <br /> 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
Expand Down Expand Up @@ -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). <br /> 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. <br /> If integer, same value will be used for both. <br /> Alternatively, define array: `[previous, future]` |

### Seed / secret length

Expand All @@ -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

Expand All @@ -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';
Expand Down
12 changes: 12 additions & 0 deletions build.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ const browsers = {
}
};

const nodejs = {
targets: {
node: '6'
}
};

module.exports = {
otplib: {
bundler: 'rollup',
Expand Down Expand Up @@ -42,5 +48,11 @@ module.exports = {
babel: {
presets: [['env', browsers]]
}
},
'otplib-expo': {
bundler: 'webpack',
babel: {
presets: [['env', nodejs]]
}
}
};
2 changes: 1 addition & 1 deletion packages/otplib-browser/randomBytes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions packages/otplib-expo/crypto.js
Original file line number Diff line number Diff line change
@@ -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
};
9 changes: 9 additions & 0 deletions packages/otplib-expo/crypto.spec.js
Original file line number Diff line number Diff line change
@@ -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');
});
});
22 changes: 22 additions & 0 deletions packages/otplib-expo/index.js
Original file line number Diff line number Diff line change
@@ -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
};
31 changes: 31 additions & 0 deletions packages/otplib-expo/randomBytes.js
Original file line number Diff line number Diff line change
@@ -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;
20 changes: 20 additions & 0 deletions packages/otplib-expo/randomBytes.spec.js
Original file line number Diff line number Diff line change
@@ -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);
});
});

0 comments on commit e17b21b

Please sign in to comment.