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

Support for Cordova Android 10 template. Fixes #99, #97, #92 AND now also for IOS #91 #100

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
13 changes: 5 additions & 8 deletions hooks/after_prepare.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
module.exports = function(context) {

var path = context.requireCordovaModule('path'),
fs = context.requireCordovaModule('fs'),
crypto = context.requireCordovaModule('crypto'),
Q = context.requireCordovaModule('q'),
var path = require('path'),
fs = require('fs'),
crypto = require('crypto'),
Q = require('q'),
cordova_util = context.requireCordovaModule('cordova-lib/src/cordova/util'),
platforms = context.requireCordovaModule('cordova-lib/src/platforms/platforms'),
Parser = context.requireCordovaModule('cordova-lib/src/cordova/metadata/parser'),
ParserHelper = context.requireCordovaModule('cordova-lib/src/cordova/metadata/parserhelper/ParserHelper'),
ConfigParser = context.requireCordovaModule('cordova-common').ConfigParser;

var deferral = new Q.defer();
Expand Down Expand Up @@ -166,4 +163,4 @@ module.exports = function(context) {

fs.writeFileSync(sourceFile, content, 'utf-8');
}
}
}
11 changes: 10 additions & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-crypt-file"
version="1.3.3">
version="1.4.0">

<name>CordovaCrypt</name>
<description>Plugin Description</description>
<author>@tkyaji</author>
<license>Apache 2.0 License</license>

<engines>
<engine name="cordova" version=">=9.0.0"/>
<engine name="cordova-android" version=">=9.0.0" />
<engine name="cordova-ios" version=">=6.1.0" />
</engines>

<platform name="ios">
<config-file target="config.xml" parent="/*">
Expand All @@ -31,6 +37,9 @@
</config-file>

<source-file src="src/android/com/tkyaji/cordova/DecryptResource.java" target-dir="src/com/tkyaji/cordova" />
<source-file src="src/android/com/tkyaji/cordova/DecryptCordovaPathHandler.java" target-dir="src/com/tkyaji/cordova" />

<framework src="androidx.webkit:webkit:${cordovaConfig.ANDROIDX_WEBKIT_VERSION}" />
</platform>

<cryptfiles>
Expand Down
126 changes: 126 additions & 0 deletions src/android/com/tkyaji/cordova/DecryptCordovaPathHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.tkyaji.cordova;

import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.net.Uri;
import android.util.Base64;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.webkit.WebResourceResponse;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.webkit.WebViewAssetLoader;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaResourceApi;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DecryptCordovaPathHandler implements WebViewAssetLoader.PathHandler {
private static final String TAG = "DecryptResource";

public CordovaWebView webView;
public CordovaInterface cordova;

private final String[] INCLUDE_FILES;
private final String[] EXCLUDE_FILES;
private final String CRYPT_KEY;
private final String CRYPT_IV;

public DecryptCordovaPathHandler(CordovaWebView webView,
CordovaInterface cordova,
String[] INCLUDE_FILES, String[] EXCLUDE_FILES,
String CRYPT_KEY, String CRYPT_IV) {
this.webView = webView;
this.cordova = cordova;
this.INCLUDE_FILES = INCLUDE_FILES;
this.EXCLUDE_FILES = EXCLUDE_FILES;
this.CRYPT_KEY = CRYPT_KEY;
this.CRYPT_IV = CRYPT_IV;
}

private boolean isCryptFiles(String uri) {
String checkPath = uri.replace("file:///android_asset/www/", "");
if (!this.hasMatch(checkPath, INCLUDE_FILES)) {
return false;
}
if (this.hasMatch(checkPath, EXCLUDE_FILES)) {
return false;
}
return true;
}

private boolean hasMatch(String text, String[] regexArr) {
for (String regex : regexArr) {
if (Pattern.compile(regex).matcher(text).find()) {
return true;
}
}
return false;
}

@Nullable
@Override
public WebResourceResponse handle(@NonNull String path) {
if (path.startsWith("+++/")) {
String newPath = "www/" + path.replace("+++/", "").split("\\?")[0];

try {
CordovaResourceApi resourceApi = this.webView.getResourceApi();
String mimeType = resourceApi.getMimeType(Uri.parse("file://" + newPath));
InputStream is = webView.getContext().getAssets().open(newPath, AssetManager.ACCESS_STREAMING);

if (!isCryptFiles(path)) {
return new WebResourceResponse(mimeType, null, is);
}

BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder strb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
strb.append(line);
}
br.close();

byte[] bytes = Base64.decode(strb.toString(), Base64.DEFAULT);

LOG.d(TAG, "decrypt: " + newPath);
ByteArrayInputStream byteInputStream = null;
try {
SecretKey skey = new SecretKeySpec(CRYPT_KEY.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey, new IvParameterSpec(CRYPT_IV.getBytes("UTF-8")));

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(cipher.doFinal(bytes));
byteInputStream = new ByteArrayInputStream(bos.toByteArray());
} catch (Exception ex) {
LOG.e(TAG, ex.getMessage());
}

return new WebResourceResponse(mimeType, null, byteInputStream);
}
catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage());
}
} else {
return null;
}

return null;
}
}
11 changes: 10 additions & 1 deletion src/android/com/tkyaji/cordova/DecryptResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.util.Base64;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaPluginPathHandler;
import org.apache.cordova.CordovaResourceApi;
import org.apache.cordova.LOG;

Expand All @@ -29,6 +30,14 @@ public class DecryptResource extends CordovaPlugin {
private static final String[] INCLUDE_FILES = new String[] { };
private static final String[] EXCLUDE_FILES = new String[] { };

@Override
public CordovaPluginPathHandler getPathHandler() {
return new CordovaPluginPathHandler(
new DecryptCordovaPathHandler(this.webView, this.cordova,
DecryptResource.INCLUDE_FILES, DecryptResource.EXCLUDE_FILES,
DecryptResource.CRYPT_KEY, DecryptResource.CRYPT_IV));
}

@Override
public Uri remapUri(Uri uri) {
if (uri.toString().indexOf("/+++/") > -1) {
Expand Down Expand Up @@ -79,7 +88,7 @@ public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IO
}

private boolean isCryptFiles(String uri) {
String checkPath = uri.replace("file:///android_asset/www/", "");
String checkPath = uri.replace("file:///android_asset/www/", "").replace("www/", "");
if (!this.hasMatch(checkPath, INCLUDE_FILES)) {
return false;
}
Expand Down
9 changes: 9 additions & 0 deletions src/ios/CDVCrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@
//

#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVViewController.h>
#import <WebKit/WebKit.h>
#import "CDVCryptURLProtocol.h"

@interface CDVCrypt : CDVPlugin

- (void)pluginInitialize;

#ifdef HASCDVUrlProtocol
#else
@property (nonatomic) NSMutableArray* stoppedTasks;
@property (nonatomic) CDVCryptURLProtocol* protocol;
#endif

@end
59 changes: 58 additions & 1 deletion src/ios/CDVCrypt.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,70 @@
//

#import "CDVCrypt.h"
#import "CDVCryptURLProtocol.h"

@implementation CDVCrypt

- (void)pluginInitialize
{
#ifdef HASCDVUrlProtocol
[NSURLProtocol registerClass:[CDVCryptURLProtocol class]];
#else
self.stoppedTasks = [[NSMutableArray alloc] init];
self.protocol = [[CDVCryptURLProtocol alloc] init];
#endif
}

#ifdef HASCDVUrlProtocol
#else
- (BOOL)overrideSchemeTask: (id <WKURLSchemeTask>)urlSchemeTask
{
if([[self.protocol class] canInitWithRequest:urlSchemeTask.request]) {
NSURL * url = urlSchemeTask.request.URL;

if([[self.protocol class] checkCryptFile:url]) {
NSError* error;

NSString * startPath = [[NSBundle mainBundle] pathForResource:((CDVViewController *) self.viewController).wwwFolderName ofType: nil];
NSString * filePath = [startPath stringByAppendingString:url.path];

NSString* content = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
if (!error) {
NSData* data = [self.protocol decryptContent:content];

NSString * length = [NSString stringWithFormat:@"%lu", (unsigned long) [data length]];
NSString * mimeType = [self.protocol getMimeTypeFromPath:url.path];
NSDictionary * headersDict = [NSDictionary dictionaryWithObjectsAndKeys:length, @"Content-Length", mimeType, @"Content-Type", nil];

NSHTTPURLResponse * response = [[NSHTTPURLResponse alloc] initWithURL:[urlSchemeTask.request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:headersDict];

// Do not use urlSchemeTask if it has been closed in stopURLSchemeTask. Otherwise the app will crash.
@try {
if(self.stoppedTasks == nil || ![self.stoppedTasks containsObject:urlSchemeTask]) {
[urlSchemeTask didReceiveResponse:response];
[urlSchemeTask didReceiveData:data];
[urlSchemeTask didFinish];
} else {
NSLog(@"CDVCrypt Task stopped %@", startPath);
}
} @catch (NSException *exception) {
NSLog(@"CDVCrypt send response exception: %@", exception.debugDescription);
} @finally {
// Cleanup
[self.stoppedTasks removeObject:urlSchemeTask];
}
}

return YES;
}
}

return NO;
}

- (void) stopSchemeTask: (id <WKURLSchemeTask>)urlSchemeTask {
NSLog(@"Stop CDVCrypt %@", urlSchemeTask.debugDescription);
[self.stoppedTasks addObject:urlSchemeTask];
}
#endif

@end
17 changes: 17 additions & 0 deletions src/ios/CDVCryptURLProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@
//
//

#if __has_include(<Cordova/CDVURLProtocol.h>)
#import <Cordova/CDVURLProtocol.h>
#define HASCDVUrlProtocol
#endif

#ifdef HASCDVUrlProtocol
@interface CDVCryptURLProtocol : CDVURLProtocol

@end
#else
@interface CDVCryptURLProtocol : NSObject

+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest;
+ (BOOL)checkCryptFile:(NSURL *)url;

- (NSData*)decryptContent:(NSString *)content;
- (NSString*)getMimeType:(NSURL *)url;
- (NSData *)decryptAES256WithKey:(NSString *)key iv:(NSString *)iv data:(NSString *)base64String;
- (NSString*)getMimeTypeFromPath:(NSString*)fullPath;

@end
#endif
27 changes: 19 additions & 8 deletions src/ios/CDVCryptURLProtocol.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
#import <CommonCrypto/CommonDigest.h>


static NSString* const kCryptKey = @"";
static NSString* const kCryptIv = @"";
static NSString* const kCryptKey = @"X7fn1HZYyiCgtoY/fzTlcnS7DM00Isbo";
static NSString* const kCryptIv = @"YiLfJKgdr+DWV+9r";

static int const kIncludeFileLength = 0;
static int const kIncludeFileLength = 1;
static int const kExcludeFileLength = 0;
static NSString* const kIncludeFiles[] = { };
static NSString* const kExcludeFiles[] = { };
static NSString* const kIncludeFiles[] = { @"\\.(htm|html|js|css)$" };
static NSString* const kExcludeFiles[] = { };


@implementation CDVCryptURLProtocol
Expand All @@ -29,10 +29,15 @@ + (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
if ([self checkCryptFile:theRequest.URL]) {
return YES;
}


#ifdef HASCDVUrlProtocol
return [super canInitWithRequest:theRequest];
#else
return NO;
#endif
}

#ifdef HASCDVUrlProtocol
- (void)startLoading
{
NSURL* url = self.request.URL;
Expand All @@ -50,9 +55,14 @@ - (void)startLoading

[super startLoading];
}
#else
- (NSData*)decryptContent:(NSString *)content {
return [self decryptAES256WithKey:kCryptKey iv:kCryptIv data:content];
}
#endif

+ (BOOL)checkCryptFile:(NSURL *)url {
if (![url.scheme isEqual: @"file"]) {
if (![url.scheme isEqual: @"app"]) {
return NO;
}

Expand Down Expand Up @@ -173,6 +183,7 @@ - (NSString*)getMimeTypeFromPath:(NSString*)fullPath
return mimeType;
}

#ifdef HASCDVUrlProtocol
- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType
{
if (mimeType == nil) {
Expand All @@ -187,6 +198,6 @@ - (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mi
}
[[self client] URLProtocolDidFinishLoading:self];
}

#endif

@end