Skip to content

Commit

Permalink
refactor: import single-file 3rd party modules
Browse files Browse the repository at this point in the history
This commit allows to:

- provide an ESM version of those modules ([1])
- reduce the attack surface in case of supply chain attacks
- reduce the size of the bundle with tree-shaking

As a downside, we won't receive security updates for those modules
anymore.

[1]: socketio/socket.io-client#1536
  • Loading branch information
darrachequesne committed Apr 13, 2022
1 parent b4b3ed5 commit df32277
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 63 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test/support/public/engine.io.min.js
lib/contrib/*
12 changes: 12 additions & 0 deletions lib/contrib/has-cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// imported from https://github.com/component/has-cors
let value = false;

try {
value = typeof XMLHttpRequest !== 'undefined' &&
'withCredentials' in new XMLHttpRequest();
} catch (err) {
// if XMLHttp support is disabled in IE then it will throw
// when trying to create
}

export const hasCORS = value;
38 changes: 38 additions & 0 deletions lib/contrib/parseqs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// imported from https://github.com/galkn/querystring
/**
* Compiles a querystring
* Returns string representation of the object
*
* @param {Object}
* @api private
*/

export function encode (obj) {
let str = '';

for (let i in obj) {
if (obj.hasOwnProperty(i)) {
if (str.length) str += '&';
str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
}
}

return str;
}

/**
* Parses a simple querystring into an object
*
* @param {String} qs
* @api private
*/

export function decode (qs) {
let qry = {};
let pairs = qs.split('&');
for (let i = 0, l = pairs.length; i < l; i++) {
let pair = pairs[i].split('=');
qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return qry;
}
68 changes: 68 additions & 0 deletions lib/contrib/parseuri.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// imported from https://github.com/galkn/parseuri
/**
* Parses an URI
*
* @author Steven Levithan <stevenlevithan.com> (MIT license)
* @api private
*/
const re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;

const parts = [
'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
];

export function parse(str) {
const src = str,
b = str.indexOf('['),
e = str.indexOf(']');

if (b != -1 && e != -1) {
str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
}

let m = re.exec(str || ''),
uri = {} as any,
i = 14;

while (i--) {
uri[parts[i]] = m[i] || '';
}

if (b != -1 && e != -1) {
uri.source = src;
uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
uri.ipv6uri = true;
}

uri.pathNames = pathNames(uri, uri['path']);
uri.queryKey = queryKey(uri, uri['query']);

return uri;
}

function pathNames(obj, path) {
const regx = /\/{2,9}/g,
names = path.replace(regx, "/").split("/");

if (path.substr(0, 1) == '/' || path.length === 0) {
names.splice(0, 1);
}
if (path.substr(path.length - 1, 1) == '/') {
names.splice(names.length - 1, 1);
}

return names;
}

function queryKey(uri, query) {
const data = {};

query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) {
if ($1) {
data[$1] = $2;
}
});

return data;
}
62 changes: 62 additions & 0 deletions lib/contrib/yeast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// imported from https://github.com/unshiftio/yeast
'use strict';

const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('')
, length = 64
, map = {};
let seed = 0
, i = 0
, prev;

/**
* Return a string representing the specified number.
*
* @param {Number} num The number to convert.
* @returns {String} The string representation of the number.
* @api public
*/
export function encode(num) {
let encoded = '';

do {
encoded = alphabet[num % length] + encoded;
num = Math.floor(num / length);
} while (num > 0);

return encoded;
}

/**
* Return the integer value specified by the given string.
*
* @param {String} str The string to convert.
* @returns {Number} The integer value represented by the string.
* @api public
*/
export function decode(str) {
let decoded = 0;

for (i = 0; i < str.length; i++) {
decoded = decoded * length + map[str.charAt(i)];
}

return decoded;
}

/**
* Yeast: A tiny growing id generator.
*
* @returns {String} A unique id.
* @api public
*/
export function yeast() {
const now = encode(+new Date());

if (now !== prev) return seed = 0, prev = now;
return now +'.'+ encode(seed++);
}

//
// Map each character to its index.
//
for (; i < length; i++) map[alphabet[i]] = i;
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export const protocol = Socket.protocol;
export { Transport } from "./transport.js";
export { transports } from "./transports/index.js";
export { installTimerFunctions } from "./util.js";
export { parse } from "./contrib/parseuri";
10 changes: 5 additions & 5 deletions lib/socket.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { transports } from "./transports/index.js";
import { installTimerFunctions, byteLength } from "./util.js";
import parseqs from "parseqs";
import parseuri from "parseuri";
import { decode } from "./contrib/parseqs.js";
import { parse } from "./contrib/parseuri.js";
import debugModule from "debug"; // debug()
import { Emitter } from "@socket.io/component-emitter";
import { protocol } from "engine.io-parser";
Expand Down Expand Up @@ -277,13 +277,13 @@ export class Socket extends Emitter<{}, {}, SocketReservedEvents> {
}

if (uri) {
uri = parseuri(uri);
uri = parse(uri);
opts.hostname = uri.host;
opts.secure = uri.protocol === "https" || uri.protocol === "wss";
opts.port = uri.port;
if (uri.query) opts.query = uri.query;
} else if (opts.host) {
opts.hostname = parseuri(opts.host).host;
opts.hostname = parse(opts.host).host;
}

installTimerFunctions(this, opts);
Expand Down Expand Up @@ -335,7 +335,7 @@ export class Socket extends Emitter<{}, {}, SocketReservedEvents> {
this.opts.path = this.opts.path.replace(/\/$/, "") + "/";

if (typeof this.opts.query === "string") {
this.opts.query = parseqs.decode(this.opts.query);
this.opts.query = decode(this.opts.query);
}

// set on handshake
Expand Down
6 changes: 3 additions & 3 deletions lib/transports/polling.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Transport } from "../transport.js";
import debugModule from "debug"; // debug()
import yeast from "yeast";
import parseqs from "parseqs";
import { yeast } from "../contrib/yeast.js";
import { encode } from "../contrib/parseqs.js";
import { encodePayload, decodePayload, RawData } from "engine.io-parser";
import XMLHttpRequest from "./xmlhttprequest.js";
import { Emitter } from "@socket.io/component-emitter";
Expand Down Expand Up @@ -235,7 +235,7 @@ export class Polling extends Transport {
port = ":" + this.opts.port;
}

const encodedQuery = parseqs.encode(query);
const encodedQuery = encode(query);
const ipv6 = this.opts.hostname.indexOf(":") !== -1;

return (
Expand Down
6 changes: 3 additions & 3 deletions lib/transports/websocket.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Transport } from "../transport.js";
import parseqs from "parseqs";
import yeast from "yeast";
import { encode } from "../contrib/parseqs.js";
import { yeast } from "../contrib/yeast.js";
import { pick } from "../util.js";
import {
defaultBinaryType,
Expand Down Expand Up @@ -220,7 +220,7 @@ export class WS extends Transport {
query.b64 = 1;
}

const encodedQuery = parseqs.encode(query);
const encodedQuery = encode(query);
const ipv6 = this.opts.hostname.indexOf(":") !== -1;

return (
Expand Down
2 changes: 1 addition & 1 deletion lib/transports/xmlhttprequest.browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// browser shim for xmlhttprequest module

import hasCORS from "has-cors";
import { hasCORS } from "../contrib/has-cors.js";
import globalThis from "../globalThis.js";

export default function(opts) {
Expand Down
2 changes: 1 addition & 1 deletion lib/xmlhttprequest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// browser shim for xmlhttprequest module

import hasCORS from "has-cors";
import { hasCORS } from "./contrib/has-cors.js";
import globalThis from "./globalThis.js";

export default function(opts) {
Expand Down
46 changes: 1 addition & 45 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,8 @@
"@socket.io/component-emitter": "~3.0.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.0",
"has-cors": "1.1.0",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~8.2.3",
"xmlhttprequest-ssl": "~2.0.0",
"yeast": "0.1.2"
"xmlhttprequest-ssl": "~2.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.9",
Expand Down

0 comments on commit df32277

Please # to comment.