UNPKG

@onehat/data

Version:

JS data modeling package with adapters for many storage mediums.

172 lines (149 loc) 4.54 kB
/** * This file is categorized as "Proprietary Framework Code" * and is subject to the terms and conditions defined in * file 'LICENSE.txt', which is part of this source code package. */ import OfflineRepository from '../../../Repository/Offline.js'; import * as SecureStore from 'expo-secure-store'; // see: https://docs.expo.io/versions/latest/sdk/securestore/ import _ from 'lodash'; const CHUNK_SEPARATOR = 'CHUNK'; /** * Repository representing Expo's SecureStore * Uses expo-secure-store package */ class SecureStoreRepository extends OfflineRepository { constructor(config = {}) { super(...arguments); _.merge(this, config); } async _storageGetValue(name) { try { if (this.debugMode) { console.log(this.name, 'SecureStore.get', name); } // Check if we need to assemble chunks const record = await SecureStore.getItemAsync(this._namespace(name)), regex = new RegExp('^' + CHUNK_SEPARATOR + '([\\d]+)$'), matches = record.match(regex); let result; if (matches && matches[1]) { const totalChunks = matches[1], chunks = []; let n, recName; for (n = 0; n < totalChunks; n++) { recName = this._namespace(name) + CHUNK_SEPARATOR + n; result = await SecureStore.getItemAsync(recName); chunks.push(result); } result = chunks.join(''); } else { result = await SecureStore.getItemAsync(this._namespace(name)); } if (this.debugMode) { console.log(this.name, 'SecureStore.get results', name, result); } let value; if (!_.isNil(result)) { try { value = JSON.parse(result); } catch (e) { value = result; // Invalid JSON, just return raw result } } return value; } catch (error) { // if (this.debugMode) { // const msg = error && error.message; // debugger; // } } } async _storageSetValue(name, value) { try { if (!_.isString(value)) { value = JSON.stringify(value); } if (this.debugMode) { console.log(this.name, 'SecureStore.set', name, value); } const totalSize = new Blob([value]).size, maxSize = 2000; let result; if (totalSize > maxSize) { // value is too big (values cannot be > 2048 bytes https://docs.expo.dev/versions/latest/sdk/securestore/) // so we need to chunk the value const totalChunks = Math.ceil(totalSize / maxSize), chunks = new Array(totalChunks); let i, o, n, chunkValue, recName; for (i = 0, o = 0; i < totalChunks; ++i, o += maxSize) { chunks[i] = value.substr(o, maxSize) } // Save a header into the normal value, which stores the number of chunks, and tells the repository to get the chunks next time it's read recName = this._namespace(name); result = await SecureStore.setItemAsync(recName, CHUNK_SEPARATOR + totalChunks); // now save the actual chunks for (n = 0; n < chunks.length; n++) { chunkValue = chunks[n]; recName = this._namespace(name) + CHUNK_SEPARATOR + n; await SecureStore.setItemAsync(recName, chunkValue); } } else { result = await SecureStore.setItemAsync(this._namespace(name), value); } // if (this.debugMode) { // console.log(this.name, 'SecureStore.set results', name, result); // } return result; } catch (error) { // if (this.debugMode) { // const msg = error && error.message; // debugger; // } } } async _storageDeleteValue(name) { try { if (this.debugMode) { console.log(this.name, 'SecureStore.delete', name); } // Check if we need to delete chunks const record = await SecureStore.getItemAsync(this._namespace(name)), regex = new RegExp('^' + CHUNK_SEPARATOR + '([\\d]+)$'), matches = record.match(regex); let result; if (matches && matches[1]) { const totalChunks = matches[1]; let n, recName; for (n = 0; n < totalChunks; n++) { recName = this._namespace(name) + CHUNK_SEPARATOR + n; result = await SecureStore.deleteItemAsync(recName); } } else { result = await SecureStore.deleteItemAsync(this._namespace(name)); } // if (this.debugMode) { // console.log(this.name, 'SecureStore.delete results', name, result); // } return result; } catch (error) { // if (this.debugMode) { // const msg = error && error.message; // debugger; // } } } async clearAll() { await this.load([]); } }; SecureStoreRepository.className = 'SecureStore'; SecureStoreRepository.type = 'secure'; export default SecureStoreRepository;