Skip to content

Commit

Permalink
Merge pull request LordKBX#1 from rorygrandin/uwp_support
Browse files Browse the repository at this point in the history
Windows support for native file hashing
  • Loading branch information
dee42 authored Jul 27, 2018
2 parents ab9ba31 + 8f398a9 commit cb05726
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 13 deletions.
5 changes: 5 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cordova-plugin-file-hash
Copyright 2018 The Apache Software Foundation

This software contains code derived from the cordova-plugin-file library (version 6.0.1).
cordova-plugin-file is released under the Apache License version 2 (see LICENSE-APACHE file).
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
This plugin provides file hash functions
##Version 0.4.1
##Platforms
|**Android**|**IOS**|
|:---:|:---:|
|>=5.0|>= 8.0|
|**Android**|**IOS**|**Windows**|
|:---:|:---:|:---:|
|>=5.0|>= 8.0|>= 10.0|


If your intrested i search help for an adaptation on Windows Phone(W10 ?), in that case leave a message [here](https://github.com/LordKBX/cordova-plugin-file-hash/issues)

###***list of functions***
|**md2**|**md5**|**sha1**|**sha256**|**sha384**|**sha512**|
|:---:|:---:|:---:|:---:|:---:|:---:|
Expand All @@ -17,27 +15,28 @@ If your intrested i search help for an adaptation on Windows Phone(W10 ?), in th

[window.]FileHash.<function>(<file_absolute_path>, successCallback, errorCallback);

![warning](https://cdn1.iconfinder.com/data/icons/nuove/32x32/actions/messagebox_warning.png) require and absolute path(file:// format, use [cordova-plugin-file](https://www.npmjs.com/package/cordova-plugin-file) for retrieve the appfolder)
![warning](https://cdn1.iconfinder.com/data/icons/nuove/32x32/actions/messagebox_warning.png) requires an absolute path(file:// format, use [cordova-plugin-file](https://www.npmjs.com/package/cordova-plugin-file) to retrieve the appfolder)

the successCallback function receive a JSON structure, here the content of the structure
the successCallback function receives a JSON object, here is the structure of the returned object:

Object{file: "<file_absolute_path>", algo: "<algorithm>", result: "<file_hash>"}

the errorCallback function receive a JSON structure, here the content of the structure
the errorCallback function receives a JSON object, here is the structure of the returned object:

Object{code: <int_return_code>, message: "<error_description>"}

###***List of error codes***
|code|message|additional informations|
|:---:|:---|:---|
|0|Execution Error|unknow error|
|0|Execution Error|unknown error|
|1|Unknown Algorithm|only if you do somthing stupid with the plugin code|
|2|File not found|on IOS was also send in case of access error|
|3|File access error|no sufficents access rights or already used file|
|4|Digest error|cryptography processing error|
|5|Not implemented error|Algorithm not implemented|

###***Exemple on Android***
![warning](https://cdn1.iconfinder.com/data/icons/nuove/32x32/actions/messagebox_warning.png) this exemple use [cordova-plugin-file](https://www.npmjs.com/package/cordova-plugin-file) for retrieve the appfolder(cordova.file.applicationDirectory)
###***Example on Android***
![warning](https://cdn1.iconfinder.com/data/icons/nuove/32x32/actions/messagebox_warning.png) this example uses [cordova-plugin-file](https://www.npmjs.com/package/cordova-plugin-file) to retrieve the appfolder(cordova.file.applicationDirectory)

FileHash.md5(cordova.file.applicationDirectory+'www/index.html',
function(e){console.log(e);})
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-file-hash",
"version": "0.4.1",
"version": "0.4.1-j5.1",
"description": "Cordova FileHash Plugin",
"cordova": {
"id": "cordova-plugin-file-hash",
Expand Down
9 changes: 8 additions & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:rim="http://www.blackberry.com/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-file-hash" version="0.4.1">
id="cordova-plugin-file-hash" version="0.4.1-j5.1">
<name>FileHash</name>
<description>Cordova FileHash Plugin</description>
<license>Apache 2.0</license>
Expand Down Expand Up @@ -35,4 +35,11 @@
<header-file src="src/ios/CDVFileHash.h" />
<source-file src="src/ios/CDVFileHash.m" />
</platform>

<!-- windows -->
<platform name="windows">
<js-module src="src/windows/FileHashProxy.js" name="FileHashProxy">
<merges target="" />
</js-module>
</platform>
</plugin>
232 changes: 232 additions & 0 deletions src/windows/FileHashProxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

/* global Windows, WinJS, MSApp */

var getFileFromPathAsync = Windows.Storage.StorageFile.getFileFromPathAsync;


function cordovaPathToNative(path) {
// turn / into \\
var cleanPath = path.replace(/\//g, '\\');
// turn \\ into \
cleanPath = cleanPath.replace(/\\+/g, '\\');
return cleanPath;
}

function nativePathToCordova (path) {
return path.replace(/\\/g, '/');
}

var driveRE = new RegExp("^[/]*([A-Z]:)");

var WinFS = function (name, root) {
this.winpath = root.winpath;
if (this.winpath && !/\/$/.test(this.winpath)) {
this.winpath += '/';
}
root.fullPath = '/';
if (!root.nativeURL) { root.nativeURL = 'file://' + sanitize(this.winpath + root.fullPath).replace(':', '%3A'); }
this.name = name;
this.root = root;
};

var AllFileSystems;

function getAllFS () {
if (!AllFileSystems) {
AllFileSystems = {
'persistent':
Object.freeze(new WinFS('persistent', {
name: 'persistent',
nativeURL: 'ms-appdata:///local',
winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.localFolder.path)
})),
'temporary':
Object.freeze(new WinFS('temporary', {
name: 'temporary',
nativeURL: 'ms-appdata:///temp',
winpath: nativePathToCordova(Windows.Storage.ApplicationData.current.temporaryFolder.path)
})),
'application':
Object.freeze(new WinFS('application', {
name: 'application',
nativeURL: 'ms-appx:///',
winpath: nativePathToCordova(Windows.ApplicationModel.Package.current.installedLocation.path)
})),
'root':
Object.freeze(new WinFS('root', {
name: 'root',
// nativeURL: 'file:///'
winpath: ''
}))
};
}
return AllFileSystems;
}

function sanitize(path) {
var slashesRE = new RegExp('/{2,}','g');
var components = path.replace(slashesRE, '/').split(/\/+/);
// Remove double dots, use old school array iteration instead of RegExp
// since it is impossible to debug them
for (var index = 0; index < components.length; ++index) {
if (components[index] === "..") {
components.splice(index, 1);
if (index > 0) {
// if we're not in the start of array then remove preceeding path component,
// In case if relative path points above the root directory, just ignore double dots
// See file.spec.111 should not traverse above above the root directory for test case
components.splice(index-1, 1);
--index;
}
}
}
return components.join('/');
}

function getFilesystemFromPath (path) {
var res;
var allfs = getAllFS();
Object.keys(allfs).some(function (fsn) {
var fs = allfs[fsn];
if (path.indexOf(fs.winpath) === 0) { res = fs; }
return res;
});
return res;
}


var msapplhRE = new RegExp('^ms-appdata://localhost/');
function pathFromURL(url) {
url=url.replace(msapplhRE,'ms-appdata:///');
var path = decodeURIComponent(url);
// support for file name with parameters
if (/\?/g.test(path)) {
path = String(path).split("?")[0];
}
if (path.indexOf("file:/")===0) {
if (path.indexOf("file://") !== 0) {
url = "file:///" + url.substr(6);
}
}

['file://','ms-appdata:///','cdvfile://localhost/'].every(function(p) {
if (path.indexOf(p)!==0)
return true;
var thirdSlash = path.indexOf("/", p.length);
if (thirdSlash < 0) {
path = "";
} else {
path = sanitize(path.substr(thirdSlash));
}
});

return path.replace(driveRE,'$1');
}

function getFilesystemFromURL (url) {
url = url.replace(msapplhRE, 'ms-appdata:///');
var res;
if (url.indexOf('file:/') === 0) { res = getFilesystemFromPath(pathFromURL(url)); } else {
var allfs = getAllFS();
Object.keys(allfs).every(function (fsn) {
var fs = allfs[fsn];
if (url.indexOf(fs.root.nativeURL) === 0 ||
url.indexOf('cdvfile://localhost/' + fs.name + '/') === 0) {
res = fs;
return false;
}
return true;
});
}
return res;
}

function makeHash(win, fail, url, algo, hashObj) {
var fs = getFilesystemFromURL(url);
var path = pathFromURL(url);
if (!fs) {
fail({code: 3, message: "File access error"});
return;
}
var wpath = cordovaPathToNative(sanitize(fs.winpath + path));

getFileFromPathAsync(wpath).then(
function (storageFile) {
Windows.Storage.FileIO.readBufferAsync(storageFile).done(
function (buffer) {
hashObj.append(buffer)
var hashText = Windows.Security.Cryptography.CryptographicBuffer.encodeToHexString(hashObj.getValueAndReset());
win({file: url, algo: algo, result: hashText});
}
);
}, function () {
fail({code: 2, message: "File not found"});
}
);
}



module.exports = {

md2: function (win, fail, args){
fail({code: 5, message: "Algorithm not implemented."});
},

md5: function (win, fail, args){
var url = args[0];
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.md5);
var hash = alg.createHash();
makeHash(win, fail, url, "md5", hash);
},

sha1: function (win, fail, args){
var url = args[0];
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.sha1);
var hash = alg.createHash();
makeHash(win, fail, url, "sha1", hash);
},

sha256: function (win, fail, args){
var url = args[0];
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.sha256);
var hash = alg.createHash();
makeHash(win, fail, url, "sha256", hash);
},

sha384: function (win, fail, args){
var url = args[0];
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.sha384);
var hash = alg.createHash();
makeHash(win, fail, url, "sha384", hash);
},

sha512: function (win, fail, args){
var url = args[0];
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.sha512);
var hash = alg.createHash();
makeHash(win, fail, url, "sha512", hash);
},
};

require("cordova/exec/proxy").add("FileHash",module.exports);

0 comments on commit cb05726

Please sign in to comment.