Skip to content

Commit

Permalink
- Fix: Add default option escapeNFDForDatabaseNames to
Browse files Browse the repository at this point in the history
    escape characters that expand on NFD normalization so as to avoid
    accidental loss of precise Unicode code points and thus potential name
    clashes on the Mac which does NFD normalization on the file system (user
    should normalize themselves if they want normalization); part of indexeddbshim#278
- Testing (Mocha, fake, mock, W3C Old, QUnit): Avoid adding ".sqlite" prefix manually
    as now adding automatically by default
  • Loading branch information
brettz9 committed Apr 8, 2017
1 parent 3c33658 commit 91b62aa
Show file tree
Hide file tree
Showing 29 changed files with 414 additions and 265 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ they were actually changes since a more recent version on `master`.
`IDBObjectStore.indexNames`)
- Fix: Escape upper-case letters as table/column names case-insensitive in
SQLite, but db/store/index names not case-insensitive in IndexedDB
- Fix: Add default option `escapeNFDForDatabaseNames` to
escape characters that expand on NFD normalization so as to avoid
accidental loss of precise Unicode code points and thus potential name
clashes on the Mac which does NFD normalization on the file system (user
should normalize themselves if they want normalization); part of #278
- Fix: Stringify calls to `IDBDatabase.createObjectStore` and
`IDBObjectstore.createIndex` as per W3C tests
- Fix: Avoid setting `source` for `open` request, as, per new spec, it is
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ browser, particularly if one changes the defaults.
the escaped filename exceeds the length of 254 characters (the shortest
typical modern file length maximum). Provide a number to change the
limit or supply `false` to disable any length checking.
- __escapeNFDForDatabaseNames__ - Boolean defaulting to true on whether
to escape NFD-escaping characters to avoid clashes on MacOS which
performs NFD on files
- __addSQLiteExtension__ - Boolean on whether to add the `.sqlite` extension
to file names; defaults to `true`

The following config items are for Node only and are mostly for development
debugging.
Expand Down
105 changes: 64 additions & 41 deletions dist/indexeddbshim-UnicodeIdentifiers-node.js

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions dist/indexeddbshim-UnicodeIdentifiers-node.min.js

Large diffs are not rendered by default.

103 changes: 63 additions & 40 deletions dist/indexeddbshim-UnicodeIdentifiers.js

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions dist/indexeddbshim-UnicodeIdentifiers.min.js

Large diffs are not rendered by default.

103 changes: 63 additions & 40 deletions dist/indexeddbshim-node.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions dist/indexeddbshim-node.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/indexeddbshim-node.min.js.map

Large diffs are not rendered by default.

99 changes: 61 additions & 38 deletions dist/indexeddbshim-noninvasive.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions dist/indexeddbshim-noninvasive.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/indexeddbshim-noninvasive.min.js.map

Large diffs are not rendered by default.

101 changes: 62 additions & 39 deletions dist/indexeddbshim.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions dist/indexeddbshim.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/indexeddbshim.min.js.map

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions npm-shrinkwrap.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"sync-promise": "https://github.com/brettz9/sync-promise#full-sync-missing-promise-features",
"typeson": "https://github.com/dfahlander/typeson",
"typeson-registry": "https://github.com/dfahlander/typeson-registry",
"unicode-9.0.0": "0.7.0",
"w3c-blob": "0.0.1",
"ws": "2.2.2",
"xmlhttprequest": "https://github.com/brettz9/node-XMLHttpRequest#local-and-prototype"
Expand Down
33 changes: 19 additions & 14 deletions src/CFG.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ const CFG = {};
// Boolean for verbose reporting
'DEBUG', // Effectively defaults to false (ignored unless `true`)

// Used when setting global shims to determine whether to try to add
// other globals shimmed by the library (`ShimDOMException`, `ShimDOMStringList`,
// `ShimEvent`, `ShimCustomEvent`, `ShimEventTarget`)
'addNonIDBGlobals', // Effectively defaults to false (ignored unless `true`)

// Determines whether the slow-performing `Object.setPrototypeOf` calls required
// for full WebIDL compliance will be used. Probably only needed for testing
// or environments where full introspection on class relationships is required;
Expand All @@ -29,14 +24,6 @@ const CFG = {};
'UnicodeIDStart', // In the non-Unicode builds, defaults to /[$A-Z_a-z]/
'UnicodeIDContinue', // In the non-Unicode builds, defaults to /[$0-9A-Z_a-z]/

// NODE-SPECIFIC CONFIG
// Boolean on whether to delete the database file itself after `deleteDatabase`;
// defaults to `true` as the database will be empty
'deleteDatabaseFiles',
// Boolean on whether to add the `.sqlite` extension to file names;
// defaults to `true`
'addSQLiteExtension',

// -----------SQL CONFIG----------
// Object (`window` in the browser) on which there may be an
// `openDatabase` method (if any) for WebSQL. (The browser
Expand All @@ -56,6 +43,14 @@ const CFG = {};
// quota every five megabytes."
'DEFAULT_DB_SIZE', // Defaults to (4 * 1024 * 1024) or (25 * 1024 * 1024) in Safari

// NODE-IMPINGING SETTINGS (created for sake of limitations in Node or desktop file
// system implementation but applied by default in browser for parity)

// Used when setting global shims to determine whether to try to add
// other globals shimmed by the library (`ShimDOMException`, `ShimDOMStringList`,
// `ShimEvent`, `ShimCustomEvent`, `ShimEventTarget`)
'addNonIDBGlobals', // Effectively defaults to false (ignored unless `true`)

// Overcoming limitations with node-sqlite3/storing database name on file systems
// https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
'escapeDatabaseName', // Defaults to prefixing database with `D_`, escaping
Expand All @@ -67,8 +62,18 @@ const CFG = {};
// (characters nevertheless commonly reserved in modern, Unicode-supporting
// systems): 0x00-0x1F 0x7F " * / : < > ? \ |
'databaseNameLengthLimit', // Defaults to 254 (shortest typical modern file length limit)
'escapeNFDForDatabaseNames', // Boolean defaulting to true on whether to escape NFD-escaping
// characters to avoid clashes on MacOS which performs NFD on files
// Boolean on whether to add the `.sqlite` extension to file names;
// defaults to `true`
'addSQLiteExtension',

// NODE-SPECIFIC CONFIG
// Boolean on whether to delete the database file itself after `deleteDatabase`;
// defaults to `true` as the database will be empty
'deleteDatabaseFiles',

// Optional Node WebSQL config
// NODE-SPECIFIC WEBSQL CONFIG
'sqlBusyTimeout', // Defaults to 1000
'sqlTrace', // Callback not used by default
'sqlProfile' // Callback not used by default
Expand Down
21 changes: 16 additions & 5 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CFG from './CFG';
import expandsOnNFD from 'unicode-9.0.0/Binary_Property/Expands_On_NFD/regex';

function escapeNameForSQLiteIdentifier (arg) {
// http://stackoverflow.com/a/6701665/271577
Expand Down Expand Up @@ -48,6 +49,12 @@ function escapeDatabaseNameForSQLAndFiles (db) {
return CFG.escapeDatabaseName(escapeSQLiteStatement(db));
}
db = 'D' + escapeNameForSQLiteIdentifier(db);
if (CFG.escapeNFDForDatabaseNames !== false) {
// ES6 copying of regex with different flags
db = db.replace(new RegExp(expandsOnNFD, 'g'), function (expandable) {
return '^4' + expandable.codePointAt().toString(16).padStart(6, '0');
});
}
if (CFG.databaseCharacterEscapeList !== false) {
db = db.replace(
(CFG.databaseCharacterEscapeList
Expand Down Expand Up @@ -78,11 +85,15 @@ function unescapeDatabaseNameForSQLAndFiles (db) {
}

return db.slice(2) // D_
.replace(/(\^+)1([0-9a-f]{2})/g, (_, esc, hex) => esc % 2 ? String.fromCharCode(parseInt(hex, 16)) : _) // databaseCharacterEscapeList
.replace(/(\^+)3\uD800([\uDC00-\uDFFF])/g, (_, esc, lowSurr) => esc % 2 ? lowSurr : _)
.replace(/(\^+)2([\uD800-\uDBFF])\uDC00/g, (_, esc, highSurr) => esc % 2 ? highSurr : _)
.replace(/(\^+)([A-Z])/g, (_, esc, upperCase) => esc % 2 ? upperCase : _)
.replace(/(\^+)0/g, (_, esc) => esc % 2 ? '\0' : _)
// CFG.databaseCharacterEscapeList
.replace(/(\^+)1([0-9a-f]{2})/g, (_, esc, hex) => esc.length % 2 ? String.fromCharCode(parseInt(hex, 16)) : _)
// CFG.escapeNFDForDatabaseNames
.replace(/(\^+)4([0-9a-f]{6})/g, (_, esc, hex) => esc.length % 2 ? String.fromCodePoint(parseInt(hex, 16)) : _)
// escapeNameForSQLiteIdentifier
.replace(/(\^+)3\uD800([\uDC00-\uDFFF])/g, (_, esc, lowSurr) => esc.length % 2 ? lowSurr : _)
.replace(/(\^+)2([\uD800-\uDBFF])\uDC00/g, (_, esc, highSurr) => esc.length % 2 ? highSurr : _)
.replace(/(\^+)([A-Z])/g, (_, esc, upperCase) => esc.length % 2 ? upperCase : _)
.replace(/(\^+)0/g, (_, esc) => esc.length % 2 ? '\0' : _)
.replace(/\^\^/g, '^');
}

Expand Down
2 changes: 1 addition & 1 deletion tests-mocha/IDBFactory/open-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ describe('IDBFactory.open', function () {
var err = null;

try {
indexedDB.open('test.sqlite', version);
indexedDB.open('test', version);
} catch (e) {
err = e;
}
Expand Down
2 changes: 1 addition & 1 deletion tests-mocha/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'use strict';

var databaseNamePrefix = 'indexeddbshim_test_database_';
var databaseSuffix = '.sqlite';
var databaseSuffix = ''; // '.sqlite' now added automatically by default
var dbNameCounter = 0;
var util;

Expand Down
2 changes: 1 addition & 1 deletion tests-polyfill/fakeIndexedDB/fakeIndexedDB.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function getFakeTestName () {
return 'test' + Math.random() + '.sqlite';
return 'test' + Math.random();
}

describe('indexedDB Tests', function () {
Expand Down
2 changes: 1 addition & 1 deletion tests-polyfill/indexedDBmock/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ global.equal = assert.equal
global.deepEqual = assert.deepEqual

global.KeyRange = IDBKeyRange;
global.dbName = "test_database.sqlite";
global.dbName = "test_database";
global.objectStoreName = "objectStore";
global.anOtherObjectStoreName = "anOtherObjectStoreName";
global.indexProperty = "name";
Expand Down
8 changes: 4 additions & 4 deletions tests-polyfill/w3c/IDBFactory.deleteDatabase.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('W3C IDBFactory.deleteDatabase Tests', function () {
// idbfactory_deletedatabase4
it('Test events opening a second database when one connection is open already', function (done) {
var db;
var openrq = indexedDB.open('db.sqlite', 3);
var openrq = indexedDB.open('db', 3);

openrq.onupgradeneeded = function(e) {
e.target.result.createObjectStore('store');
Expand All @@ -86,7 +86,7 @@ describe('W3C IDBFactory.deleteDatabase Tests', function () {
openrq.onblocked = function () { throw new Error("open.blocked"); };

function Second(e) {
var deleterq = indexedDB.deleteDatabase('db.sqlite');
var deleterq = indexedDB.deleteDatabase('db');

deleterq.onsuccess = function(e) { done(); }

Expand All @@ -109,7 +109,7 @@ describe('W3C IDBFactory.deleteDatabase Tests', function () {
it('IDBVersionChangeEvent fired in upgradeneeded, versionchange and deleteDatabase', function (done) {
var db;

var openrq = indexedDB.open('db.sqlite', 3);
var openrq = indexedDB.open('db', 3);

openrq.onupgradeneeded = function(e) {
assert.equal(e.oldVersion, 0, "old version (upgradeneeded)");
Expand Down Expand Up @@ -139,7 +139,7 @@ describe('W3C IDBFactory.deleteDatabase Tests', function () {
openrq.onblocked = function () { throw new Error("open.blocked"); };

function deleteDB (e) {
var deleterq = indexedDB.deleteDatabase('db.sqlite');
var deleterq = indexedDB.deleteDatabase('db');

deleterq.onsuccess = function(e) {
assert.equal(e.oldVersion, 3, "old version (delete.success)");
Expand Down
4 changes: 2 additions & 2 deletions tests-polyfill/w3c/IDBFactory.open.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ describe('W3C IDBFactory.open Tests', function () {

// idbfactory_open2
it("database 'name' and 'version' are correctly set", function (done) {
var open_rq = createdb(done, 'database_name.sqlite', 13);
var open_rq = createdb(done, 'database_name', 13);

open_rq.onupgradeneeded = function(e) {};
open_rq.onsuccess = function(e) {
var db = e.target.result;
assert.equal(db.name, 'database_name.sqlite', 'db.name');
assert.equal(db.name, 'database_name', 'db.name');
assert.equal(db.version, 13, 'db.version');
done();
}
Expand Down
2 changes: 1 addition & 1 deletion tests-polyfill/w3c/IDBTransaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('W3C IDBTransaction Tests', function () {
// idbtransaction
it('IDBTransaction', function (done) {
var db;
var open_rq = indexedDB.open("idbtransaction-" + new Date().getTime() + Math.random() + '.sqlite');
var open_rq = indexedDB.open("idbtransaction-" + new Date().getTime() + Math.random());

assert.equal(open_rq.transaction, null, "IDBOpenDBRequest.transaction");
assert.equal(open_rq.source, null, "IDBOpenDBRequest.source");
Expand Down
12 changes: 6 additions & 6 deletions tests-polyfill/w3c/TransactionBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('W3C Transaction Behavior Tests', function () {
var db, db_got_versionchange, db2,
events = [];

var openrq = indexedDB.open('db.sqlite', 3);
var openrq = indexedDB.open('db', 3);

// 1
openrq.onupgradeneeded = function(e) {
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('W3C Transaction Behavior Tests', function () {
assert(db instanceof FDBDatabase);
assert.deepEqual(db.objectStoreNames, [ "store" ]);

var openrq2 = indexedDB.open('db.sqlite', 4);
var openrq2 = indexedDB.open('db', 4);

// 4
openrq2.onupgradeneeded = function(e) {
Expand Down Expand Up @@ -75,7 +75,7 @@ describe('W3C Transaction Behavior Tests', function () {
]);

if (db2) db2.close();
indexedDB.deleteDatabase('db.sqlite');
indexedDB.deleteDatabase('db');
setTimeout(function() {
done();
}, 10);
Expand All @@ -92,7 +92,7 @@ describe('W3C Transaction Behavior Tests', function () {
var db, db_got_versionchange, db2,
events = [];

var openrq = indexedDB.open('db.sqlite', 3);
var openrq = indexedDB.open('db', 3);

// 1
openrq.onupgradeneeded = function(e) {
Expand Down Expand Up @@ -131,7 +131,7 @@ describe('W3C Transaction Behavior Tests', function () {
assert(db instanceof FDBDatabase);
assert.deepEqual(db.objectStoreNames, [ "store" ]);

var openrq2 = indexedDB.open('db.sqlite', 4);
var openrq2 = indexedDB.open('db', 4);

// 4
openrq2.onblocked = function(e) {
Expand Down Expand Up @@ -168,7 +168,7 @@ describe('W3C Transaction Behavior Tests', function () {
]);

if (db2) db2.close();
indexedDB.deleteDatabase('db.sqlite');
indexedDB.deleteDatabase('db');
setTimeout(function() { done(); }, 10);
};

Expand Down
2 changes: 1 addition & 1 deletion tests-polyfill/w3c/support.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var dbPrefix = 'testdb-';
var dbSuffix = '.sqlite';
var dbSuffix = '';

function getDBName () {
return dbPrefix + new Date().getTime() + dbSuffix;
Expand Down
2 changes: 1 addition & 1 deletion tests-qunit/sampleData.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env qunit */
/* eslint-disable no-var */
var DB = { // eslint-disable-line no-unused-vars
NAME: 'dbname.sqlite',
NAME: 'dbname',
OBJECT_STORE_1: 'objectStore1',
OBJECT_STORE_2: 'objectStore2',
OBJECT_STORE_3: 'objectStore3',
Expand Down

0 comments on commit 91b62aa

Please sign in to comment.