Browse Source

improve backup file output for rules: array instead of one huge string

pull/2/head
Raymond Hill 7 years ago
parent
commit
749e8d5cc4
No known key found for this signature in database GPG Key ID: 25E1490B761470C2
  1. 253
      src/js/matrix.js
  2. 2
      src/js/messaging.js
  3. 19
      src/js/storage.js

253
src/js/matrix.js

@ -1,7 +1,7 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014-2017 Raymond Hill
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,7 +20,6 @@
*/
/* global punycode */
/* jshint bitwise: false */
'use strict';
@ -31,13 +30,11 @@
/******************************************************************************/
var µm = µMatrix;
var magicId = 'axyorpwxtmnf';
var uniqueIdGenerator = 1;
var selfieVersion = 1;
/******************************************************************************/
var Matrix = function() {
this.id = uniqueIdGenerator++;
this.reset();
this.sourceRegister = '';
this.decomposedSourceRegister = [''];
@ -103,10 +100,10 @@ var switchStateToNameMap = new Map([
[ 2, 'false' ]
]);
var nameToSwitchStateMap = {
'true': 1,
'false': 2
};
var nameToSwitchStateMap = new Map([
[ 'true', 1 ],
[ 'false', 2 ]
]);
/******************************************************************************/
@ -594,15 +591,13 @@ Matrix.prototype.extractAllSourceHostnames = (function() {
/******************************************************************************/
Matrix.prototype.toString = function() {
var out = [];
var rule, type, switchName, val;
var srcHostname, desHostname;
for ( rule of this.rules.keys() ) {
srcHostname = this.srcHostnameFromRule(rule);
desHostname = this.desHostnameFromRule(rule);
for ( type of typeBitOffsets.keys() ) {
val = this.evaluateCell(srcHostname, desHostname, type);
Matrix.prototype.toArray = function() {
let out = [];
for ( let rule of this.rules.keys() ) {
let srcHostname = this.srcHostnameFromRule(rule);
let desHostname = this.desHostnameFromRule(rule);
for ( let type of typeBitOffsets.keys() ) {
let val = this.evaluateCell(srcHostname, desHostname, type);
if ( val === 0 ) { continue; }
out.push(
punycode.toUnicode(srcHostname) + ' ' +
@ -612,176 +607,140 @@ Matrix.prototype.toString = function() {
);
}
}
for ( srcHostname of this.switches.keys() ) {
for ( switchName of switchBitOffsets.keys() ) {
val = this.evaluateSwitch(switchName, srcHostname);
for ( let srcHostname of this.switches.keys() ) {
for ( let switchName of switchBitOffsets.keys() ) {
let val = this.evaluateSwitch(switchName, srcHostname);
if ( val === 0 ) { continue; }
out.push(switchName + ': ' + srcHostname + ' ' + switchStateToNameMap.get(val));
out.push(
switchName + ': ' +
srcHostname + ' ' +
switchStateToNameMap.get(val)
);
}
}
return out.sort().join('\n');
return out;
};
/******************************************************************************/
Matrix.prototype.fromArray = function(lines, append) {
let matrix = append === true ? this : new Matrix();
for ( let line of lines ) {
matrix.fromLine(line);
}
if ( append !== true ) {
this.assign(matrix);
}
this.modifiedTime = Date.now();
};
/******************************************************************************/
Matrix.prototype.toString = function() {
return this.toArray().join('\n');
};
/******************************************************************************/
Matrix.prototype.fromString = function(text, append) {
var matrix = append ? this : new Matrix();
var textEnd = text.length;
var lineBeg = 0, lineEnd;
var line, pos;
var fields, fieldVal;
var switchName;
var srcHostname = '';
var desHostname = '';
var type, state;
let matrix = append === true ? this : new Matrix();
let textEnd = text.length;
let lineBeg = 0;
while ( lineBeg < textEnd ) {
lineEnd = text.indexOf('\n', lineBeg);
if ( lineEnd < 0 ) {
let lineEnd = text.indexOf('\n', lineBeg);
if ( lineEnd === -1 ) {
lineEnd = text.indexOf('\r', lineBeg);
if ( lineEnd < 0 ) {
if ( lineEnd === -1 ) {
lineEnd = textEnd;
}
}
line = text.slice(lineBeg, lineEnd).trim();
let line = text.slice(lineBeg, lineEnd).trim();
lineBeg = lineEnd + 1;
pos = line.indexOf('# ');
let pos = line.indexOf('# ');
if ( pos !== -1 ) {
line = line.slice(0, pos).trim();
}
if ( line === '' ) {
continue;
}
fields = line.split(/\s+/);
// Less than 2 fields makes no sense
if ( fields.length < 2 ) {
continue;
}
if ( line === '' ) { continue; }
fieldVal = fields[0];
// Special directives:
// title
pos = fieldVal.indexOf('title:');
if ( pos !== -1 ) {
// TODO
continue;
}
// Name
pos = fieldVal.indexOf('name:');
if ( pos !== -1 ) {
// TODO
continue;
}
matrix.fromLine(line);
}
// Switch on/off
if ( append !== true ) {
this.assign(matrix);
}
// `switch:` srcHostname state
// state = [`true`, `false`]
switchName = '';
if ( fieldVal === 'switch:' || fieldVal === 'matrix:' ) {
fieldVal = 'matrix-off:';
}
pos = fieldVal.indexOf(':');
if ( pos !== -1 ) {
switchName = fieldVal.slice(0, pos);
}
if ( switchBitOffsets.has(switchName) ) {
srcHostname = punycode.toASCII(fields[1]);
this.modifiedTime = Date.now();
};
// No state field: reject
fieldVal = fields[2];
if ( fieldVal === null ) {
continue;
}
// Unknown state: reject
if ( nameToSwitchStateMap.hasOwnProperty(fieldVal) === false ) {
continue;
}
/******************************************************************************/
// Backward compatibility:
// `chromium-behind-the-scene` is now `behind-the-scene`
if ( srcHostname === 'chromium-behind-the-scene' ) {
srcHostname = 'behind-the-scene';
}
// https://github.com/gorhill/uMatrix/issues/759
// Backward compatibility: 'plugin' => 'media'
matrix.setSwitch(switchName, srcHostname, nameToSwitchStateMap[fieldVal]);
continue;
}
Matrix.prototype.fromLine = function(line) {
let fields = line.split(/\s+/);
if ( fields.length < 3 ) { return false; }
let field0 = fields[0];
// Unknown directive
if ( fieldVal.endsWith(':') ) {
continue;
// Switches
let pos = field0.indexOf(':');
if ( pos !== -1 ) {
let switchName = field0.slice(0, pos);
let srcHostname = punycode.toASCII(fields[1]);
let state = fields[2];
if (
switchBitOffsets.has(switchName) === false ||
nameToSwitchStateMap.has(state) === false
) {
return false;
}
this.setSwitch(
switchName,
srcHostname,
nameToSwitchStateMap.get(state)
);
return true;
}
// Valid rule syntax:
// srcHostname desHostname [type [state]]
// type = a valid request type
// state = [`block`, `allow`, `inherit`]
// srcHostname desHostname type
// type = a valid request type
// state = `allow`
// srcHostname desHostname
// type = `*`
// state = `allow`
// Lines with invalid syntax silently ignored
srcHostname = punycode.toASCII(fields[0]);
desHostname = punycode.toASCII(fields[1]);
// Rules
if ( fields.length < 4 ) { return false; }
fieldVal = fields[2];
let srcHostname = punycode.toASCII(fields[0]);
let desHostname = punycode.toASCII(fields[1]);
let type = fields[2];
if ( fieldVal !== undefined ) {
type = fieldVal;
// https://github.com/gorhill/uMatrix/issues/759
// Backward compatibility.
if ( type === 'plugin' ) {
type = 'media';
}
// Unknown type: reject
if ( typeBitOffsets.has(type) === false ) {
continue;
}
} else {
type = '*';
if ( type !== undefined ) {
if ( type === 'plugin' ) {
type = 'media';
} else if ( typeBitOffsets.has(type) === false ) {
return false;
}
} else {
type = '*';
}
fieldVal = fields[3];
let state = fields[3];
if ( fieldVal !== undefined ) {
// Unknown state: reject
if ( nameToStateMap.hasOwnProperty(fieldVal) === false ) {
continue;
}
state = nameToStateMap[fieldVal];
} else {
state = 2;
if ( state !== undefined ) {
if ( nameToStateMap.hasOwnProperty(state) === false ) {
return false;
}
matrix.setCell(srcHostname, desHostname, type, state);
}
if ( !append ) {
this.assign(matrix);
state = nameToStateMap[state];
} else {
state = 2;
}
this.modifiedTime = Date.now();
this.setCell(srcHostname, desHostname, type, state);
return true;
};
/******************************************************************************/
Matrix.prototype.toSelfie = function() {
return {
magicId: magicId,
version: selfieVersion,
switches: Array.from(this.switches),
rules: Array.from(this.rules)
};
@ -790,7 +749,7 @@ Matrix.prototype.toSelfie = function() {
/******************************************************************************/
Matrix.prototype.fromSelfie = function(selfie) {
if ( selfie.magicId !== magicId ) { return false; }
if ( selfie.version !== selfieVersion ) { return false; }
this.switches = new Map(selfie.switches);
this.rules = new Map(selfie.rules);
this.modifiedTime = Date.now();

2
src/js/messaging.js

@ -864,7 +864,7 @@ var onMessage = function(request, sender, callback) {
version: vAPI.app.version,
when: Date.now(),
settings: µm.userSettings,
rules: µm.pMatrix.toString(),
rules: µm.pMatrix.toArray().sort(),
rawSettings: µm.rawSettings
};
break;

19
src/js/storage.js

@ -242,22 +242,27 @@
/******************************************************************************/
µMatrix.saveMatrix = function() {
µMatrix.XAL.keyvalSetOne('userMatrix', this.pMatrix.toString());
vAPI.storage.set({ userMatrix: this.pMatrix.toArray() });
};
µMatrix.loadMatrix = function(callback) {
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var µm = this;
var onLoaded = function(bin) {
if ( bin.hasOwnProperty('userMatrix') ) {
let µm = this;
let onLoaded = function(bin) {
if ( bin instanceof Object === false ) {
return callback();
}
if ( typeof bin.userMatrix === 'string' ) {
µm.pMatrix.fromString(bin.userMatrix);
µm.tMatrix.assign(µm.pMatrix);
callback();
} else if ( Array.isArray(bin.userMatrix) ) {
µm.pMatrix.fromArray(bin.userMatrix);
}
µm.tMatrix.assign(µm.pMatrix);
callback();
};
this.XAL.keyvalGetOne('userMatrix', onLoaded);
vAPI.storage.get('userMatrix', onLoaded);
};
/******************************************************************************/

Loading…
Cancel
Save