Skip to content
This repository has been archived by the owner on Nov 7, 2023. It is now read-only.

Commit

Permalink
Merge pull request #16 from emeraldsanto/dev
Browse files Browse the repository at this point in the history
Version 2.4.0
  • Loading branch information
emeraldsanto authored May 30, 2020
2 parents f3a3582 + 6494955 commit 902dbe8
Show file tree
Hide file tree
Showing 7 changed files with 1,144 additions and 955 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void setItem(String key, String value, Promise promise) {
}

else {
promise.reject(new Exception(String.format("An error occured while saving %s", key)));
promise.reject(new Exception(String.format("An error occurred while saving %s", key)));
}
}

Expand Down Expand Up @@ -101,4 +101,23 @@ public void removeItem(String key, Promise promise) {
promise.reject(new Exception(String.format("An error occured while removing %s", key)));
}
}

public void clear(Promise promise) {
if (this.sharedPreferences == null) {
promise.reject(new NullPointerException("Could not initialize SharedPreferences"));
return;
}

SharedPreferences.Editor editor = this.sharedPreferences.edit();
editor.clear();
boolean saved = editor.commit();

if (saved) {
promise.resolve(null);
}

else {
promise.reject(new Exception("An error occured while clearing SharedPreferences"));
}
}
}
19 changes: 19 additions & 0 deletions ios/RNEncryptedStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,23 @@ + (BOOL)requiresMainQueueSetup
reject(@"remove_error", @"An error occured while removing", error);
}
}

RCT_EXPORT_METHOD(clear:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *secItemClasses = @[
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity
];

// Maps through all Keychain classes and deletes all items that match
for (id secItemClass in secItemClasses) {
NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass};
SecItemDelete((__bridge CFDictionaryRef)spec);
}

resolve();
}
@end
34 changes: 33 additions & 1 deletion lib/EncryptedStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,30 @@ describe("lib/EncryptedStorage", () => {
.toBeUndefined();
});

it("should throw an error if it could not retrieve the stored value", async () => {
it("should throw an error if it could not retrieve the stored value", () => {
RNEncryptedStorage.removeItem.mockImplementationOnce(() => Promise.reject(new Error("Remove error")));

return expect(EncryptedStorage.removeItem("key"))
.rejects
.toThrow("Remove error");
});
});

describe("clear()", () => {
it("should return no error if it could clear the storage", () => {
return expect(EncryptedStorage.clear())
.resolves
.toBeUndefined();
});

it("should throw an error if it could not clear the storage", () => {
RNEncryptedStorage.clear.mockImplementationOnce(() => Promise.reject(new Error("Clear error")));

return expect(EncryptedStorage.clear())
.rejects
.toThrow("Clear error");
});
});
});

describe("using callbacks", () => {
Expand Down Expand Up @@ -125,5 +141,21 @@ describe("lib/EncryptedStorage", () => {
});
});
});

describe("clear()", () => {
it("should return no error if it could clear the storage", () => {
EncryptedStorage.clear(error => {
expect(error).toBeUndefined();
});
});

it("should throw an error if it could not clear the storage", () => {
RNEncryptedStorage.clear.mockImplementationOnce(() => Promise.reject(new Error("Clear error")));

EncryptedStorage.clear(error => {
expect(error.message).toEqual("Clear error");
});
});
});
});
});
101 changes: 68 additions & 33 deletions lib/EncryptedStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,92 @@ if (!RNEncryptedStorage) {
throw new Error("RNEncryptedStorage is undefined");
}

export type StorageErrorCallback = (error?: Error) => void;
export type StorageValueCallback = (error?: Error, value?: string) => void;

export default class EncryptedStorage {

/**
* Writes data to the disk, using SharedPreferences or KeyChain, depending on the platform.
* @param {string} key - A string that will be associated to the value for later retrieval.
* @param {string} value - The data to store.
*/
static async setItem(key: string, value: string, cb?: (error: Error | undefined) => void): Promise<void> {
return new Promise(async (resolve, reject) => {
try {
await RNEncryptedStorage.setItem(key, value);
cb?.(undefined);
resolve(undefined);
} catch (error) {
cb?.(error);
reject(error);
}
});
static setItem(key: string, value: string): Promise<void>;

/**
* Writes data to the disk, using SharedPreferences or KeyChain, depending on the platform.
* @param {string} key - A string that will be associated to the value for later retrieval.
* @param {string} value - The data to store.
* @param {Function} cb - The function to call when the operation completes.
*/
static setItem(key: string, value: string, cb: StorageErrorCallback): void;
static setItem(key: string, value: string, cb?: StorageErrorCallback): void | Promise<void> {
if (cb) {
RNEncryptedStorage.setItem(key, value).then(cb).catch(cb);
return;
}

return RNEncryptedStorage.setItem(key, value);
}

/**
* Retrieves data from the disk, using SharedPreferences or KeyChain, depending on the platform and returns it as the specified type.
* @param {string} key - A string that is associated to a value.
*/
static async getItem(key: string, cb?: (error: Error | undefined, value: string | undefined) => void): Promise<string | undefined> {
return new Promise(async (resolve, reject) => {
try {
const value = await RNEncryptedStorage.getItem(key);
cb && cb(undefined, value ?? undefined);
resolve(value ?? undefined);
} catch (error) {
cb && cb(error, undefined);
reject(error);
}
});
static getItem(key: string): Promise<string | null>;

/**
* Retrieves data from the disk, using SharedPreferences or KeyChain, depending on the platform and returns it as the specified type.
* @param {string} key - A string that is associated to a value.
* @param {Function} cb - The function to call when the operation completes.
*/
static getItem(key: string, cb: StorageValueCallback): void;
static getItem(key: string, cb?: StorageValueCallback): void | Promise<string | null> {
if (cb) {
RNEncryptedStorage.getItem(key).then(cb).catch(cb);
return;
}

return RNEncryptedStorage.getItem(key);
}

/**
* Deletes data from the disk, using SharedPreferences or KeyChain, depending on the platform.
* @param {string} key - A string that is associated to a value.
*/
static async removeItem(key: string, cb?: (error: Error | undefined) => void): Promise<void> {
return new Promise(async (resolve, reject) => {
try {
await RNEncryptedStorage.removeItem(key);
cb && cb(undefined);
resolve(undefined);
} catch (error) {
cb && cb(error);
reject(error);
}
});
static removeItem(key: string): Promise<void>;

/**
* Deletes data from the disk, using SharedPreferences or KeyChain, depending on the platform.
* @param {string} key - A string that is associated to a value.
* @param {Function} cb - The function to call when the operation completes.
*/
static removeItem(key: string, cb: StorageErrorCallback): void;
static removeItem(key: string, cb?: StorageErrorCallback): void | Promise<void> {
if (cb) {
RNEncryptedStorage.removeItem(key).then(cb).catch(cb);
return;
}

return RNEncryptedStorage.removeItem(key);
}

/**
* Clears all data from disk, using SharedPreferences or KeyChain, depending on the platform.
*/
static clear(): Promise<void>;

/**
* Clears all data from disk, using SharedPreferences or KeyChain, depending on the platform.
* @param {Function} cb - The function to call when the operation completes.
*/
static clear(cb: (error?: Error) => void): void;
static clear(cb?: (error?: Error) => void): void | Promise<void> {
if (cb) {
RNEncryptedStorage.clear().then(cb).catch(cb);
return;
}

return RNEncryptedStorage.clear();
}
}
15 changes: 8 additions & 7 deletions lib/__mocks__/react-native.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
module.exports = {
NativeModules: {
RNEncryptedStorage: {
setItem: jest.fn(() => Promise.resolve()),
getItem: jest.fn(() => Promise.resolve('{ "foo": 1 }')),
removeItem: jest.fn(() => Promise.resolve()),
},
},
NativeModules: {
RNEncryptedStorage: {
setItem: jest.fn(() => Promise.resolve()),
getItem: jest.fn(() => Promise.resolve('{ "foo": 1 }')),
removeItem: jest.fn(() => Promise.resolve()),
clear: jest.fn(() => Promise.resolve())
}
}
};
Loading

0 comments on commit 902dbe8

Please sign in to comment.