Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2: Drop IE8-IE10 support. #345

Open
wants to merge 22 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ If you're looking to change some code in RavelinJS, read this first.
* [7. Prefer testing in unit tests.](#7-prefer-testing-in-unit-tests)
* [8. Use integration tests where necessary.](#8-use-integration-tests-where-necessary)
* [Process](#process)
* [9. New pull requests should target branch v1.](#9-new-pull-requests-should-target-branch-v1)
* [9. New pull requests should target branch v2.](#9-new-pull-requests-should-target-branch-v2)
* [10. Understand the file structure.](#10-understand-the-file-structure)
* [11. Keep Dependencies Up-to-Date](#11-keep-dependencies-up-to-date)
* [12. Publish new versions according to semantic versioning.](#12-publish-new-versions-according-to-semantic-versioning)
Expand Down Expand Up @@ -103,12 +103,12 @@ Running `test/server.js` will give you an ngrok URL through which you can access
the Mocha unit test page in any browser. Use this if you want to step through
using a remote browser.

Unit tests run in the browser and therefore must be written in IE-compatible
Unit tests run in the browser and therefore must be written in IE11-compatible
JavaScript, as with code in the lib. The tests have access to:

* `Ravelin` from the local build/ravelin-core+track+encrypt+promise.min.js (symlinked via test/ravelin.js);
* the [Mocha test framework](https://mochajs.org/);
* [jQuery v1](https://api.jquery.com/category/version/1.12-and-2.2/) for simple DOM manipulation;
* [jQuery v2](https://api.jquery.com/category/version/1.12-and-2.2/) for simple DOM manipulation;
* [xhook](https://github.com/jpillora/xhook) for mocking HTTP requests; and
* [expect.js](https://www.npmjs.com/package/expect.js) for assertions.

Expand Down Expand Up @@ -184,10 +184,12 @@ HTML file you write for you test, but most will use:
test/ravelin.js)
* Utilities in test/common.js, such as query-string parsing and error-sniffing.

## 9. New pull requests should target branch v1.
## 9. New pull requests should target branch v2.

The main branches of the ravelinjs repo follow their major semver version:
[v1](https://github.com/unravelin/ravelinjs/tree/v1) (latest, default) and
[v2](https://github.com/unravelin/ravelinjs/tree/v2) (latest, default - largely
the same as v1 but without IE8-10 support),
[v1](https://github.com/unravelin/ravelinjs/tree/v1) and
[v0](https://github.com/unravelin/ravelinjs/tree/v0).

If you wish to propose a change, make your change on a new fork/branch of the
Expand Down Expand Up @@ -317,7 +319,7 @@ tl;dr: ./lib for real code; ./test for test code.
│ ├── encrypt.test.js
│ ├── track.test.js
│ │
│ └── karma.conf.js
│ └── karma.conf.cjs
│ Karma JS configuration for loading the *.test.js unit test files
│ into a browser and executing them.
Expand Down Expand Up @@ -385,7 +387,7 @@ We publish new versions project to two places:
* [npm](https://www.npmjs.com/package/ravelinjs/v/1).

New versions should be published after merging new features or bug fixes into
the [v1](https://github.com/unravelin/ravelinjs/tree/v1/) branch, using [np (a
the [v2](https://github.com/unravelin/ravelinjs/tree/v2/) branch, using [np (a
better `npm publish`)](https://www.npmjs.com/package/np). `np` does quite a lot
for you, including run `npm test` which will require that you have the
`BROWSERSTACK` envvars set. To test it, run:
Expand Down
47 changes: 21 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ a successful Ravelin integration.

Please feel welcome to create issues or submit pull requests on [the
project](https://github.com/unravelin/ravelinjs). The [Contribution
Guidelines](https://github.com/unravelin/ravelinjs/blob/v1/CONTRIBUTING.md)
Guidelines](https://github.com/unravelin/ravelinjs/blob/v2/CONTRIBUTING.md)
detail how to write and test code for ravelinjs.

Note that this documentation is for version 1 of ravelinjs. For version 0,
Note that this documentation is for version 2 of RavelinJS. For version 0,
please see its [usage guide](https://developer.ravelin.com/libraries-and-sdks/ravelinjs/v0/usage-guide/),
[reference](https://developer.ravelin.com/libraries-and-sdks/ravelinjs/v0/reference/)
and [source](https://github.com/unravelin/ravelinjs/tree/v0).
Expand All @@ -39,8 +39,9 @@ and [source](https://github.com/unravelin/ravelinjs/tree/v0).
* [`ravelin.track.paste(event: ClipboardEvent)`](#ravelintrackpasteevent-clipboardevent)
* [Vendored Code](#vendored-code)
* [Upgrading](#upgrading)
* [Upgrading to ravelinjs v1 from ravelinjs v0](#upgrading-to-ravelinjs-v1-from-ravelinjs-v0)
* [Upgrading to ravelinjs v1 from cdn.ravelin.net script snippet](#upgrading-to-ravelinjs-v1-from-cdnravelinnet-script-snippet)
* [Upgrading to RavelinJS v2 from RavelinJS v1](#upgrading-to-ravelinjs-v2-from-ravelinjs-v1)
* [Upgrading to RavelinJS v2 from RavelinJS v0](#upgrading-to-ravelinjs-v2-from-ravelinjs-v0)
* [Upgrading to RavelinJS v2 from cdn.ravelin.net script snippet](#upgrading-to-ravelinjs-v2-from-cdnravelinnet-script-snippet)

## Quickstart

Expand Down Expand Up @@ -163,19 +164,11 @@ contents using:

## Browser Compatibility

RavelinJS v1.0.0 is [tested on IE8-11 and all newer
browsers](test/wdio.conf.js). We plan to drop support for IE8-IE10 soon, so
please contact us if you still support these browsers.
RavelinJS v2.0.0 is [tested on IE11 and all newer browsers](test/wdio.conf.js).

A Promise/A+ polyfill is required for Internet Explorer support. If you do not
have one, or are not sure, then use a +promise ravelinjs bundle.

Card encryption uses window.crypto where available, and otherwise falls back to
a pseudo-random number generator which collects user movements and keypresses as
a source of entropy. If insufficient events have been collected before
encryption is attempted, an Error is thrown to prevent insecure transmission of
cardholder data.

## Reference

### `var ravelin = new Ravelin({cfg: object})`
Expand Down Expand Up @@ -394,12 +387,6 @@ var action = fetch('https://api.ravelin.com/v2/checkout?score=true', {
});
```

Note that [browsers which do not support
`window.crypto`](https://caniuse.com/cryptography) (including IE8-IE10) rely on
a pseudo-random number generator based on collecting user events from the page
and that if this generator has not collected enough events it may throw an
exception when trying to encrypt.
icio marked this conversation as resolved.
Show resolved Hide resolved

### `ravelin.track.load()`

Send a page-load event. This is automatically triggered when Ravelin is
Expand All @@ -419,8 +406,7 @@ sent.
### `ravelin.track.paste(event: ClipboardEvent)`

Send a paste event to Ravelin. This is done automatically if the paste happens
in the same frame Ravelin is instantiated - except on IE8 which does not support
paste-event listening at the document level.
in the same frame Ravelin is instantiated.

To correctly identify the paste contents you should annotate your forms with
attributes:
Expand Down Expand Up @@ -448,11 +434,20 @@ it relies:
## Upgrading

Note that the format of the deviceId was changed in v1 to include a "rjs-"
prefix. If you do any validation or parsing that checks for a particular
format of the deviceId, please remove this logic and instead treat the deviceId as
an opaque string.
prefix. If you do any validation or parsing that checks for a particular format
of the deviceId, please remove this logic and instead treat the deviceId as an
opaque string.

### Upgrading to RavelinJS v2 from RavelinJS v1

There are no breaking API changes between v1 and v2. This major version release
was made to signify the end of our support for browsers IE8 to IE10. IE11
continues to be supported. If you are unable to upgrade to v2 because you want
to continue supporting any these browsers, please let us know.

If you don't care about IE8-IE10, just go ahead and upgrade.

### Upgrading to ravelinjs v1 from ravelinjs v0
### Upgrading to RavelinJS v2 from RavelinJS v0

If you are using RavelinJS v0 from a script or loaded via npm then equivalent
functionality is now covered by bundles with the core+track+encrypt components.
Expand All @@ -479,7 +474,7 @@ the upgrade:
[`ravelin.core.id()`][ravelin.core.id] to send the device via your server.
* `ravelinjs.setOrderId(orderId)` → Removed.

### Upgrading to ravelinjs v1 from cdn.ravelin.net script snippet
### Upgrading to RavelinJS v2 from cdn.ravelin.net script snippet

If you previously used a snippet such as

Expand Down
61 changes: 10 additions & 51 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function Core(cfg) {
this.version = cfg.version || RAVELINJS_VERSION;
this.key = cfg.key;
this.api = cfg.api || apiFromKey(this.key);
this.api = this.api[0] + this.api.substr(1).replace(/^\/+|\/$/g, '');
this.api = this.api[0] + this.api.substring(1).replace(/^\/+|\/$/g, '');
this.sendRetryMs = cfg.sendRetryMs || 150;
this.cookie = cfg.cookie || 'ravelinDeviceId';
this.sessionCookie = cfg.sessionCookie || 'ravelinSessionId';
Expand Down Expand Up @@ -99,12 +99,12 @@ Core.prototype.ids = function() {
// Restore d from s.
var sep = s.indexOf(':');
if (sep != -1) {
d = s.substr(0, sep);
d = s.substring(0, sep);
}

// Strip d: from the beginning of s.
if (d && hasPrefix(s, d+':')) {
s = s.substr(d.length+1);
s = s.substring(d.length+1);
}
}

Expand All @@ -123,7 +123,7 @@ Core.prototype.ids = function() {
* @returns {boolean}
*/
function hasPrefix(s, prefix) {
return s.substr(0, prefix.length) === prefix;
return s.substring(0, prefix.length) === prefix;
}

/**
Expand Down Expand Up @@ -196,11 +196,11 @@ var defaultAPI = 'https://live.ravelin.click';
* @returns {string} API URL
*/
function apiFromKey(key) {
if (!key || key.substr(0, 16) != 'publishable_key_') {
if (!key || key.substring(0, 16) != 'publishable_key_') {
return defaultAPI;
}

var words = key.substr(16).split('_');
var words = key.substring(16).split('_');
if (words.length < 2) {
return defaultAPI;
}
Expand All @@ -213,8 +213,6 @@ function apiFromKey(key) {
return 'https://' + encodeURIComponent(env) + '.ravelin.click';
}

var _XDomainRequest = typeof XDomainRequest !== 'undefined' && XDomainRequest;

/**
* @typedef {Object} CoreResponse
* @property {number} status
Expand Down Expand Up @@ -289,11 +287,9 @@ Core.prototype.bind = function() {
* send makes a HTTP request and returns a Promise that resolves to the response
* body or is rejected with any errors or non-2xx status codes.
*
* For backwards compatibility with IE8-9 whose XDomainRequest does not allow us
* to add headers to cross-domain requests - and to avoid OPTIONS preflight
* requests on browsers that do - we do not accept setting headers here. Instead
* we put the key in the query string and expect the server to support whatever
* headers the browser cares to add.
* To avoid OPTIONS preflight requests, we do not accept setting headers here.
* Instead we put the key in the query string and expect the server to support
* whatever headers the browser cares to add.
*
* @param {string} method
* @param {string} path
Expand All @@ -312,12 +308,7 @@ Core.prototype.send = function(method, path, body) {

var c = this;
return promiseRetry(c.Promise, function(retry, attempt) {
return (
// Make the request.
!sameOrigin(url) && _XDomainRequest) ?
c._sendXDR(method, url, stringify(body)) :
c._sendXHR(method, url, stringify(body)
).then(function(r) {
return c._sendXHR(method, url, stringify(body)).then(function(r) {
r.attempt = attempt;

// Resolve/reject based on status.
Expand Down Expand Up @@ -373,38 +364,6 @@ Core.prototype._sendXHR = function(method, url, body) {
});
};

/**
* _sendXDR wraps an XHR in a Promise.
*
* @param {string} method
* @param {string} url
* @param {object} body
* @returns {Promise<CoreResponse>}
*/
Core.prototype._sendXDR = function(method, url, body) {
return new this.Promise(function(resolve, reject) {
var r = new _XDomainRequest();
r.onload = function() {
resolve({status: r.status || 200, text: r.responseText});
};
r.onerror = function() {
reject({status: r.status, text: r.responseText});
};
r.onprogress = function() {
// Needed to ensure onload fires.
};

r.open(method, url);
setTimeout(function () {
// Wrapped in a timeout to prevent an issue with the interface where some
// requests are lost if multiple XDomainRequests are being sent at the
// same time.
// https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest.
r.send(body);
}, 0);
});
};

/**
* stringify is JSON.stringify with prototype safety.
*
Expand Down
Loading