mirror of
https://github.com/standardnotes/mobile.git
synced 2026-04-19 21:58:51 -04:00
Updates
This commit is contained in:
@@ -4,8 +4,7 @@ import ModelManager from "./lib/sfjs/modelManager"
|
||||
import Server from "./lib/sfjs/httpManager"
|
||||
import Sync from './lib/sfjs/syncManager'
|
||||
import Storage from "./lib/sfjs/storageManager"
|
||||
import Auth from "./lib/authManager"
|
||||
import Theme from "./models/subclass/theme"
|
||||
import Auth from "./lib/sfjs/authManager"
|
||||
import KeysManager from './lib/keysManager'
|
||||
|
||||
export default class GlobalStyles {
|
||||
@@ -54,7 +53,7 @@ export default class GlobalStyles {
|
||||
let content = Object.assign({}, parsedTheme);
|
||||
parsedTheme.content = content;
|
||||
|
||||
var theme = new Theme(parsedTheme);
|
||||
var theme = new SNTheme(parsedTheme);
|
||||
if(needsMigration) {
|
||||
theme.setMobileRules(parsedTheme.mobileRules);
|
||||
theme.mobileRules = null;
|
||||
@@ -78,7 +77,7 @@ export default class GlobalStyles {
|
||||
constructor() {
|
||||
KeysManager.get().registerAccountRelatedStorageKeys(["activeTheme"]);
|
||||
|
||||
ModelManager.get().addItemSyncObserver("themes", "SN|Theme", function(items){
|
||||
ModelManager.get().addItemSyncObserver("themes", "SN|Theme", function(allItems, validItems, deletedItems, source){
|
||||
if(this.activeTheme && this.activeTheme.isSwapIn) {
|
||||
var matchingTheme = _.find(this.themes(), {uuid: this.activeTheme.uuid});
|
||||
if(matchingTheme) {
|
||||
@@ -136,7 +135,7 @@ export default class GlobalStyles {
|
||||
|
||||
var constants = this.defaultConstants();
|
||||
|
||||
this._systemTheme = new Theme({
|
||||
this._systemTheme = new SNTheme({
|
||||
uuid: 0,
|
||||
content: {
|
||||
isDefault: true,
|
||||
|
||||
13
src/app.js
13
src/app.js
@@ -9,7 +9,9 @@ import {Navigation, ScreenVisibilityListener} from 'react-native-navigation';
|
||||
import {registerScreens} from './screens';
|
||||
|
||||
import KeysManager from './lib/keysManager'
|
||||
import Auth from './lib/authManager'
|
||||
import Auth from './lib/sfjs/authManager'
|
||||
import ModelManager from './lib/sfjs/modelManager'
|
||||
import Sync from './lib/sfjs/syncManager'
|
||||
import ReviewManager from './lib/reviewManager';
|
||||
import GlobalStyles from "./Styles"
|
||||
import Icons from "./Icons"
|
||||
@@ -73,11 +75,14 @@ export default class App {
|
||||
this.listener.register();
|
||||
|
||||
// Listen to sign out event
|
||||
this.signoutObserver = Auth.getInstance().addEventObserver([Auth.DidSignOutEvent, Auth.WillSignInEvent], function(event){
|
||||
if(event == Auth.DidSignOutEvent) {
|
||||
this.signoutObserver = Auth.get().addEventHandler((event) => {
|
||||
if(event == SFAuthManager.DidSignOutEvent) {
|
||||
this.optionsState.reset();
|
||||
KeysManager.get().clearAccountKeysAndData();
|
||||
ModelManager.get().handleSignout();
|
||||
Sync.get().handleSignout();
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,6 @@ export default class NoteCell extends React.PureComponent {
|
||||
// We want to show "Deleting.." on top of note cell after the user confirms the dialogue
|
||||
this.forceUpdate();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -171,7 +170,7 @@ export default class NoteCell extends React.PureComponent {
|
||||
{this.props.renderTags && note.tags.length > 0 &&
|
||||
<View style={this.styles.noteTags}>
|
||||
<Text numberOfLines={1} style={this.aggregateStyles(this.styles.noteTag)}>
|
||||
{SNTag.arrayToDisplayString(note.tags)}
|
||||
{this.props.tagsString}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export default class NoteList extends Component {
|
||||
title={item.title}
|
||||
text={item.text}
|
||||
tags={item.tags}
|
||||
tagsString={item.tagsString()}
|
||||
pinned={item.pinned}
|
||||
deleted={item.deleted}
|
||||
archived={item.archived}
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
SFItemParams,
|
||||
SFAlertManager,
|
||||
SFStorageManager,
|
||||
SFHttpManager
|
||||
SFHttpManager,
|
||||
SFAuthManager
|
||||
} from 'standard-file-js';
|
||||
|
||||
global.SFItem = SFItem;
|
||||
@@ -17,6 +18,7 @@ global.SFSyncManager = SFSyncManager;
|
||||
global.SFAlertManager = SFAlertManager;
|
||||
global.SFStorageManager = SFStorageManager;
|
||||
global.SFHttpManager = SFHttpManager;
|
||||
global.SFAuthManager = SFAuthManager;
|
||||
|
||||
import SF from "./lib/sfjs/sfjs"
|
||||
global.SFJS = SF.get();
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
import SF from './sfjs/sfjs'
|
||||
import Server from './sfjs/httpManager'
|
||||
import Storage from './sfjs/storageManager'
|
||||
import Sync from './sfjs/syncManager'
|
||||
import ModelManager from './sfjs/modelManager'
|
||||
import AlertManager from './sfjs/alertManager'
|
||||
|
||||
import {Platform} from 'react-native';
|
||||
import Keychain from "./keychain"
|
||||
import KeysManager from "./keysManager"
|
||||
|
||||
let accountRelatedStorageKeys = [];
|
||||
|
||||
export default class Auth {
|
||||
|
||||
static instance = null;
|
||||
|
||||
static DidSignOutEvent = "DidSignOutEvent";
|
||||
static WillSignInEvent = "WillSignInEvent";
|
||||
static DidSignInEvent = "DidSignInEvent";
|
||||
|
||||
static getInstance() {
|
||||
if (this.instance == null) {
|
||||
this.instance = new Auth();
|
||||
}
|
||||
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
static _defaultServer() {
|
||||
if (__DEV__) {
|
||||
if(Platform.OS === "android") {
|
||||
return "http://10.0.2.2:3000"
|
||||
} else {
|
||||
return "http://localhost:3000"
|
||||
}
|
||||
} else {
|
||||
return "https://sync.standardnotes.org";
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.eventSubscribers = [];
|
||||
}
|
||||
|
||||
addEventObserver(events, callback) {
|
||||
var observer = {key: new Date(), events, callback: callback};
|
||||
this.eventSubscribers.push(observer);
|
||||
return observer;
|
||||
}
|
||||
|
||||
removeEventObserver(observer) {
|
||||
_.pull(this.eventSubscribers, observer);
|
||||
}
|
||||
|
||||
serverUrl() {
|
||||
var user = KeysManager.get().user;
|
||||
return (user && user.server) || Auth._defaultServer();
|
||||
}
|
||||
|
||||
urlForPath(path, serverUrl) {
|
||||
function joinPaths(parts){
|
||||
var separator = "/";
|
||||
var replace = new RegExp(separator+'{1,}', 'g');
|
||||
return parts.join(separator).replace(replace, separator);
|
||||
}
|
||||
|
||||
if(!serverUrl) {
|
||||
serverUrl = this.serverUrl();
|
||||
}
|
||||
return joinPaths([serverUrl, path]);
|
||||
}
|
||||
|
||||
offline() {
|
||||
// an offline user could have keys saved if using passcode lock
|
||||
var keys = KeysManager.get().activeKeys() || {};
|
||||
return !keys.jwt;
|
||||
}
|
||||
|
||||
protocolVersion() {
|
||||
var authParams = KeysManager.get().activeAuthParams();
|
||||
if(authParams && authParams.version) {
|
||||
return authParams.version;
|
||||
}
|
||||
|
||||
var keys = KeysManager.get().activeKeys();
|
||||
if(keys && keys.ak) {
|
||||
// If there's no version stored, and there's an ak, it has to be 002. Newer versions would have thier version stored in authParams.
|
||||
return "002";
|
||||
} else {
|
||||
return "001";
|
||||
}
|
||||
}
|
||||
|
||||
validateLogin = (authParams, strictSignIn, callback) => {
|
||||
if(!SF.get().supportedVersions().includes(authParams.version)) {
|
||||
var message;
|
||||
if(SF.get().isVersionNewerThanLibraryVersion(authParams.version)) {
|
||||
// The user has a new account type, but is signing in to an older client.
|
||||
message = "This version of the application does not support your newer account type. Please upgrade to the latest version of Standard Notes to sign in.";
|
||||
} else {
|
||||
// The user has a very old account type, which is no longer supported by this client
|
||||
message = "The protocol version associated with your account is outdated and no longer supported by this application. Please visit standardnotes.org/help/security for more information.";
|
||||
}
|
||||
callback({message: message});
|
||||
return;
|
||||
}
|
||||
|
||||
// need to put this in a block due to asyncrounous confirm alert
|
||||
var otherValidation = () => {
|
||||
var minimum = SF.get().costMinimumForVersion(authParams.version);
|
||||
if(authParams.pw_cost < minimum) {
|
||||
let message = "Unable to login due to insecure password parameters. Please visit standardnotes.org/help/security for more information.";
|
||||
callback({message: message});
|
||||
return;
|
||||
}
|
||||
|
||||
if(strictSignIn) {
|
||||
// Refuse sign in if authParams.version is anything but the latest version
|
||||
var latestVersion = SF.get().version();
|
||||
if(authParams.version !== latestVersion) {
|
||||
let message = `Strict sign in refused server sign in parameters. The latest security version is ${latestVersion}, but your account is reported to have version ${authParams.version}. If you'd like to proceed with sign in anyway, please disable strict sign in and try again.`;
|
||||
callback({message: message});
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback(null);
|
||||
}
|
||||
|
||||
if(SF.get().isProtocolVersionOutdated(authParams.version)) {
|
||||
let message = `The encryption version for your account, ${authParams.version}, is outdated and requires upgrade. You may proceed with login, but are advised to perform a security update using the web or desktop application. Please visit standardnotes.org/help/security for more information.`
|
||||
AlertManager.get().confirm({
|
||||
title: "Update Needed",
|
||||
text: message,
|
||||
confirmButtonText: "Sign In",
|
||||
onConfirm: () => {
|
||||
otherValidation();
|
||||
},
|
||||
onCancel: () => {
|
||||
callback({});
|
||||
}
|
||||
})
|
||||
return;
|
||||
} else {
|
||||
otherValidation();
|
||||
}
|
||||
}
|
||||
|
||||
login = (email, inputtedPassword, server, strictSignIn, extraParams, callback) => {
|
||||
|
||||
this.postEvent(Auth.WillSignInEvent);
|
||||
|
||||
var root = this;
|
||||
|
||||
this.getAuthParams(email, server, extraParams, (authParams, error) => {
|
||||
if(error) {
|
||||
callback(null, error);
|
||||
return;
|
||||
}
|
||||
|
||||
authParams.identifier = email;
|
||||
|
||||
this.validateLogin(authParams, strictSignIn, (validationError) => {
|
||||
if(validationError) {
|
||||
callback(null, validationError);
|
||||
return;
|
||||
}
|
||||
|
||||
SF.get().crypto.computeEncryptionKeysForUser(inputtedPassword, authParams).then((keys) => {
|
||||
root.performLoginRequest(email, keys.pw, server, extraParams, async (response, error) => {
|
||||
if(error) {
|
||||
callback(null, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if(response.user) {
|
||||
await root.saveAuthParameters({token: response.token, email: email, server: server, authParams: authParams, keys: keys});
|
||||
root.postEvent(Auth.DidSignInEvent);
|
||||
}
|
||||
callback(response.user, error);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
register = async (email, inputtedPassword, server, callback) => {
|
||||
var root = this;
|
||||
|
||||
// if(__DEV__) { authParams.pw_cost = 3000; }
|
||||
|
||||
SF.get().crypto.generateInitialKeysAndAuthParamsForUser(email, inputtedPassword).then((results) => {
|
||||
let keys = results.keys;
|
||||
let authParams = results.authParams;
|
||||
|
||||
root.performRegistrationRequest(email, keys.pw, authParams, server, async function(response, error) {
|
||||
if(error) {
|
||||
callback(null, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if(response.user) {
|
||||
await root.saveAuthParameters({token: response.token, email: email, server: server, authParams: authParams, keys: keys});
|
||||
}
|
||||
callback(response.user, error);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async performLoginRequest(email, pw, server, extraParams, callback) {
|
||||
var url = this.urlForPath("auth/sign_in", server);
|
||||
Server.get().postAbsolute(url, _.merge({email: email, password: pw}, extraParams), function(response){
|
||||
callback(response, null);
|
||||
}, function(error){
|
||||
callback(null, error.error);
|
||||
})
|
||||
}
|
||||
|
||||
async performRegistrationRequest(email, pw, authParams, server, callback) {
|
||||
var url = this.urlForPath("auth/", server);
|
||||
Server.get().postAbsolute(url, _.merge({email: email, password: pw}, authParams), function(response){
|
||||
callback(response, null);
|
||||
}, function(error){
|
||||
callback(null, error.error);
|
||||
})
|
||||
}
|
||||
|
||||
async saveAuthParameters({token, email, server, authParams, keys} = {}) {
|
||||
try {
|
||||
this._keys = keys;
|
||||
|
||||
return await Promise.all([
|
||||
KeysManager.get().persistAccountKeys(_.merge(keys, {jwt: token})),
|
||||
KeysManager.get().setAccountAuthParams(authParams),
|
||||
KeysManager.get().saveUser({server: server, email: email})
|
||||
]);
|
||||
|
||||
} catch(e) {
|
||||
console.log("Error saving auth paramters", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getAuthParams(email, server, extraParams, callback) {
|
||||
var url = this.urlForPath("auth/params", server);
|
||||
Server.get().getAbsolute(url, _.merge({email: email}, extraParams), (response) => {
|
||||
callback(response, null);
|
||||
}, (response) => {
|
||||
console.log("Error getting auth params", response);
|
||||
var error = response.error || {message: response};
|
||||
callback(null, error);
|
||||
})
|
||||
}
|
||||
|
||||
signout() {
|
||||
ModelManager.get().handleSignout();
|
||||
KeysManager.get().clearAccountKeysAndData();
|
||||
|
||||
return Storage.get().clearAllModels().then(() => {
|
||||
Sync.get().handleSignout();
|
||||
this.postEvent(Auth.DidSignOutEvent);
|
||||
});
|
||||
}
|
||||
|
||||
postEvent(event) {
|
||||
this.eventSubscribers.forEach(function(observer){
|
||||
if(observer.events.includes(event)) {
|
||||
observer.callback(event);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,13 +28,13 @@ export default class ComponentManager {
|
||||
|
||||
this.handlers = [];
|
||||
|
||||
ModelManager.get().addItemSyncObserver("component-manager", "*", (allItems, source) => {
|
||||
ModelManager.get().addItemSyncObserver("component-manager", "*", (allItems, validItems, deletedItems, source) => {
|
||||
|
||||
/* If the source of these new or updated items is from a Component itself saving items, we don't need to notify
|
||||
components again of the same item. Regarding notifying other components than the issuing component, other mapping sources
|
||||
will take care of that, like ModelManager.MappingSourceRemoteSaved
|
||||
*/
|
||||
if(source == ModelManager.MappingSourceComponentRetrieved) {
|
||||
if(source == SFModelManager.MappingSourceComponentRetrieved) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,7 @@ export default class ComponentManager {
|
||||
jsonForItem(item, component, source) {
|
||||
var params = {uuid: item.uuid, content_type: item.content_type, created_at: item.created_at, updated_at: item.updated_at, deleted: item.deleted};
|
||||
params.content = item.createContentJSONFromProperties();
|
||||
/* Legacy is using component.url key, so if it's present, use it, otherwise use uuid */
|
||||
params.clientData = item.getDomainDataItem(component.url || component.uuid, ClientDataDomain) || {};
|
||||
params.clientData = item.getDomainDataItem(component.getClientDataKey(), ClientDataDomain) || {};
|
||||
|
||||
/* This means the this function is being triggered through a remote Saving response, which should not update
|
||||
actual local content values. The reason is, Save responses may be delayed, and a user may have changed some values
|
||||
@@ -88,7 +87,7 @@ export default class ComponentManager {
|
||||
|
||||
3/7/18: Add MappingSourceLocalSaved as well to handle fully offline saving. github.com/standardnotes/forum/issues/169
|
||||
*/
|
||||
if(source && (source == ModelManager.MappingSourceRemoteSaved || source == ModelManager.MappingSourceLocalSaved)) {
|
||||
if(source && (source == SFModelManager.MappingSourceRemoteSaved || source == SFModelManager.MappingSourceLocalSaved)) {
|
||||
params.isMetadataUpdate = true;
|
||||
}
|
||||
this.removePrivatePropertiesFromResponseItems([params], component);
|
||||
@@ -191,7 +190,7 @@ export default class ComponentManager {
|
||||
|
||||
*/
|
||||
|
||||
if(message.action === "stream-context-item") {
|
||||
if(message.action === "stream-context-item") {
|
||||
this.handleStreamContextItemMessage(component, message);
|
||||
} else if(message.action === "set-component-data") {
|
||||
this.handleSetComponentDataMessage(component, message);
|
||||
@@ -274,7 +273,7 @@ export default class ComponentManager {
|
||||
We map the items here because modelManager is what updates the UI. If you were to instead get the items directly,
|
||||
this would update them server side via sync, but would never make its way back to the UI.
|
||||
*/
|
||||
var localItems = ModelManager.get().mapResponseItemsToLocalModels(responseItems, ModelManager.MappingSourceComponentRetrieved);
|
||||
var localItems = ModelManager.get().mapResponseItemsToLocalModels(responseItems, SFModelManager.MappingSourceComponentRetrieved);
|
||||
|
||||
for(var item of localItems) {
|
||||
var responseItem = _.find(responseItems, {uuid: item.uuid});
|
||||
@@ -288,7 +287,7 @@ export default class ComponentManager {
|
||||
Sync.get().sync().then((response) => {
|
||||
// Allow handlers to be notified when a save begins and ends, to update the UI
|
||||
var saveMessage = Object.assign({}, message);
|
||||
saveMessage.action = response && response.error ? "save-error" : "save-success";
|
||||
saveMessage.action = (response && response.error) ? "save-error" : "save-success";
|
||||
this.replyToMessage(component, message, {error: response.error})
|
||||
this.handleMessage(component, saveMessage);
|
||||
});
|
||||
|
||||
@@ -13,18 +13,21 @@ export default class AlertManager extends SFAlertManager {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
confirm({title, text, confirmButtonText = "OK", onConfirm, onCancel} = {}) {
|
||||
// On iOS, confirm should go first. On Android, cancel should go first.
|
||||
let buttons = [
|
||||
{text: 'Cancel', onPress: onCancel},
|
||||
{text: confirmButtonText, onPress: onConfirm},
|
||||
];
|
||||
Alert.alert(
|
||||
title,
|
||||
text,
|
||||
buttons,
|
||||
{ cancelable: true }
|
||||
)
|
||||
async confirm({title, text, confirmButtonText = "OK", onConfirm, onCancel} = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// On iOS, confirm should go first. On Android, cancel should go first.
|
||||
let buttons = [
|
||||
{text: 'Cancel', onPress: () => {
|
||||
reject();
|
||||
onCancel && onCancel();
|
||||
}},
|
||||
{text: confirmButtonText, onPress: () => {
|
||||
resolve();
|
||||
onConfirm && onConfirm();
|
||||
}},
|
||||
];
|
||||
Alert.alert(title, text, buttons, { cancelable: true })
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
58
src/lib/sfjs/authManager.js
Normal file
58
src/lib/sfjs/authManager.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import {Platform} from 'react-native';
|
||||
import KeysManager from "../keysManager"
|
||||
import Storage from './storageManager'
|
||||
import Server from './httpManager'
|
||||
import AlertManager from './alertManager'
|
||||
|
||||
export default class Auth extends SFAuthManager {
|
||||
|
||||
static instance = null;
|
||||
static get() {
|
||||
if(this.instance == null) {
|
||||
this.instance = new Auth(Storage.get(), Server.get(), AlertManager.get());
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
defaultServer() {
|
||||
if (__DEV__) {
|
||||
if(Platform.OS === "android") {
|
||||
return "http://10.0.2.2:3000"
|
||||
} else {
|
||||
return "http://localhost:3000"
|
||||
}
|
||||
} else {
|
||||
return "https://sync.standardnotes.org";
|
||||
}
|
||||
}
|
||||
|
||||
serverUrl() {
|
||||
var user = KeysManager.get().user;
|
||||
return (user && user.server) || this.defaultServer();
|
||||
}
|
||||
|
||||
offline() {
|
||||
// an offline user could have keys saved if using passcode lock
|
||||
var keys = KeysManager.get().activeKeys() || {};
|
||||
return !keys.jwt;
|
||||
}
|
||||
|
||||
async getAuthParams() {
|
||||
return KeysManager.get().activeAuthParams();
|
||||
}
|
||||
|
||||
async handleAuthResponse(response, email, url, authParams, keys) {
|
||||
super.handleAuthResponse(response, email, url, authParams, keys);
|
||||
try {
|
||||
this._keys = keys;
|
||||
return await Promise.all([
|
||||
KeysManager.get().persistAccountKeys(_.merge(keys, {jwt: response.token})),
|
||||
KeysManager.get().setAccountAuthParams(authParams),
|
||||
KeysManager.get().saveUser({server: url, email: email})
|
||||
]);
|
||||
} catch(e) {
|
||||
console.log("Error saving auth paramters", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import Storage from "./storageManager"
|
||||
import Theme from "../../models/subclass/theme"
|
||||
import "../../models/extend/item.js";
|
||||
|
||||
SFModelManager.ContentTypeClassMapping = {
|
||||
"Note" : SNNote,
|
||||
"Tag" : SNTag,
|
||||
"SN|Theme" : Theme,
|
||||
"SN|Theme" : SNTheme,
|
||||
"SN|Component" : SNComponent
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ export default class SF extends StandardFile {
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
supportsPasswordDerivationCost(cost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SFReactNativeCrypto extends SFAbstractCrypto {
|
||||
|
||||
@@ -12,6 +12,13 @@ export default class Storage extends SFStorageManager {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
AsyncStorage.getAllKeys().then((keys) => {
|
||||
console.log("all model keys", keys);
|
||||
})
|
||||
}
|
||||
|
||||
async getItem(key) {
|
||||
try {
|
||||
return AsyncStorage.getItem(key);
|
||||
@@ -102,9 +109,7 @@ export default class Storage extends SFStorageManager {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
return Promise.all(items.map((item) => {
|
||||
console.log("Saving model", JSON.stringify(item));
|
||||
return AsyncStorage.setItem(this.keyForItem(item), JSON.stringify(item));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import ModelManager from './modelManager'
|
||||
import Storage from './storageManager'
|
||||
import AlertManager from './alertManager'
|
||||
|
||||
import Auth from '../authManager'
|
||||
import Auth from '../sfjs/authManager'
|
||||
import KeysManager from '../keysManager'
|
||||
|
||||
export default class Sync extends SFSyncManager {
|
||||
@@ -24,7 +24,6 @@ export default class Sync extends SFSyncManager {
|
||||
KeysManager.get().registerAccountRelatedStorageKeys(["syncToken", "cursorToken"]);
|
||||
|
||||
this.setKeyRequestHandler((request) => {
|
||||
console.log(request);
|
||||
var keys;
|
||||
if(request == SFSyncManager.KeyRequestLoadSaveAccount || request == SFSyncManager.KeyRequestLoadLocal) {
|
||||
keys = KeysManager.get().activeKeys();
|
||||
@@ -34,7 +33,7 @@ export default class Sync extends SFSyncManager {
|
||||
}
|
||||
|
||||
let auth_params = KeysManager.get().activeAuthParams();
|
||||
let offline = Auth.getInstance().offline();
|
||||
let offline = Auth.get().offline();
|
||||
|
||||
return {keys, auth_params, offline}
|
||||
})
|
||||
@@ -46,7 +45,7 @@ export default class Sync extends SFSyncManager {
|
||||
}
|
||||
|
||||
async getServerURL() {
|
||||
return Auth.getInstance().serverUrl();
|
||||
return Auth.get().serverUrl();
|
||||
}
|
||||
|
||||
handleSignout() {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import SF from "../../lib/sfjs/sfjs"
|
||||
|
||||
export default class Theme extends SNTheme {
|
||||
|
||||
setMobileRules(rules) {
|
||||
this.setAppDataItem("mobileRules", rules);
|
||||
}
|
||||
|
||||
getMobileRules() {
|
||||
return this.getAppDataItem("mobileRules") || {constants: {}, rules: {}};
|
||||
}
|
||||
|
||||
// Same as getMobileRules but without default value
|
||||
hasMobileRules() {
|
||||
return this.getAppDataItem("mobileRules");
|
||||
}
|
||||
|
||||
setNotAvailOnMobile(na) {
|
||||
this.setAppDataItem("notAvailableOnMobile", na);
|
||||
}
|
||||
|
||||
getNotAvailOnMobile() {
|
||||
return this.getAppDataItem("notAvailableOnMobile");
|
||||
}
|
||||
|
||||
/* We must not use .active because if you set that to true, it will also activate that theme on desktop/web */
|
||||
setMobileActive(active) {
|
||||
this.setAppDataItem("mobileActive", active);
|
||||
}
|
||||
|
||||
isMobileActive() {
|
||||
return this.getAppDataItem("mobileActive");
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,25 @@ export default class Abstract extends Component {
|
||||
|
||||
}
|
||||
|
||||
setNavBarSubtitle(title) {
|
||||
if(!this.visible || !this.willBeVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.navigator.setSubTitle({
|
||||
subtitle: title
|
||||
});
|
||||
|
||||
if(!this.didSetNavBarStyle) {
|
||||
this.didSetNavBarStyle = true;
|
||||
var color = GlobalStyles.constantForKey(App.isIOS ? "mainTextColor" : "navBarTextColor");
|
||||
this.props.navigator.setStyle({
|
||||
navBarSubtitleColor: GlobalStyles.hexToRGBA(color, 0.5),
|
||||
navBarSubtitleFontSize: 12
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
dismissModal() {
|
||||
this.props.navigator.dismissModal({animationType: "slide-down"})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import Sync from '../lib/sfjs/syncManager'
|
||||
import ModelManager from '../lib/sfjs/modelManager'
|
||||
import AlertManager from '../lib/sfjs/alertManager'
|
||||
|
||||
import Auth from '../lib/authManager'
|
||||
import Auth from '../lib/sfjs/authManager'
|
||||
import KeysManager from '../lib/keysManager'
|
||||
|
||||
import SectionHeader from "../components/SectionHeader";
|
||||
@@ -42,7 +42,7 @@ export default class Account extends Abstract {
|
||||
loadInitialState() {
|
||||
super.loadInitialState();
|
||||
|
||||
this.mergeState({params: {server: Auth.getInstance().serverUrl()}})
|
||||
this.mergeState({params: {server: Auth.get().serverUrl()}})
|
||||
|
||||
this.syncEventHandler = Sync.get().addEventHandler((event, data) => {
|
||||
if(event == "local-data-loaded") {
|
||||
@@ -50,17 +50,18 @@ export default class Account extends Abstract {
|
||||
} else if(event == "sync-session-invalid") {
|
||||
if(!this.didShowSessionInvalidAlert) {
|
||||
this.didShowSessionInvalidAlert = true;
|
||||
AlertManager.get().confirm(
|
||||
"Session Expired",
|
||||
"Your session has expired. New changes will not be pulled in. Please sign out and sign back in to refresh your session.", "Sign Out",
|
||||
() => {
|
||||
AlertManager.get().confirm({
|
||||
title: "Session Expired",
|
||||
text: "Your session has expired. New changes will not be pulled in. Please sign out and sign back in to refresh your session.",
|
||||
confirmButtonText: "Sign Out",
|
||||
onConfirm: () => {
|
||||
this.didShowSessionInvalidAlert = false;
|
||||
Auth.getInstance().signout();
|
||||
Auth.get().signout();
|
||||
},
|
||||
() => {
|
||||
onCancel: () => {
|
||||
this.didShowSessionInvalidAlert = false;
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -157,9 +158,11 @@ export default class Account extends Abstract {
|
||||
// Unlock sync after all sign in processes are complete.
|
||||
Sync.get().lockSyncing();
|
||||
|
||||
Auth.getInstance().login(email, password, params.server, strict, extraParams, (user, error) => {
|
||||
Auth.get().login(params.server, email, password, strict, extraParams).then((response) => {
|
||||
|
||||
if(!response || response.error) {
|
||||
var error = response ? response.error : {message: "An unknown error occured."}
|
||||
|
||||
if(error) {
|
||||
Sync.get().unlockSyncing();
|
||||
|
||||
if(error.tag == "mfa-required" || error.tag == "mfa-invalid") {
|
||||
@@ -207,10 +210,11 @@ export default class Account extends Abstract {
|
||||
|
||||
var params = this.state.params;
|
||||
|
||||
Auth.getInstance().register(params.email, params.password, params.server, (user, error) => {
|
||||
Auth.get().register( params.server, params.email, params.password).then((response) => {
|
||||
this.mergeState({registering: false, confirmRegistration: false});
|
||||
|
||||
if(error) {
|
||||
if(!response || response.error) {
|
||||
var error = response ? response.error : {message: "An unknown error occured."}
|
||||
Alert.alert('Oops', error.message, [{text: 'OK'}])
|
||||
return;
|
||||
}
|
||||
@@ -258,7 +262,7 @@ export default class Account extends Abstract {
|
||||
text: "Signing out will remove all data from this device, including notes and tags. Make sure your data is synced before proceeding.",
|
||||
confirmButtonText: "Sign Out",
|
||||
onConfirm: () => {
|
||||
Auth.getInstance().signout().then(() => {
|
||||
Auth.get().signout().then(() => {
|
||||
this.forceUpdate();
|
||||
})
|
||||
}
|
||||
@@ -266,13 +270,13 @@ export default class Account extends Abstract {
|
||||
}
|
||||
|
||||
async onExportPress(encrypted, callback) {
|
||||
var version = Auth.getInstance().protocolVersion();
|
||||
var auth_params = await Auth.get().getAuthParams();
|
||||
var keys = encrypted ? KeysManager.get().activeKeys() : null;
|
||||
|
||||
var items = [];
|
||||
|
||||
for(var item of ModelManager.get().allItems) {
|
||||
var itemParams = new SFItemParams(item, keys, version);
|
||||
var itemParams = new SFItemParams(item, keys, auth_params);
|
||||
var params = await itemParams.paramsForExportFile();
|
||||
items.push(params);
|
||||
}
|
||||
@@ -443,7 +447,7 @@ export default class Account extends Abstract {
|
||||
return (<LockedView />);
|
||||
}
|
||||
|
||||
let signedIn = !Auth.getInstance().offline();
|
||||
let signedIn = !Auth.get().offline();
|
||||
var themes = GlobalStyles.get().themes();
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import App from "../app"
|
||||
import SF from '../lib/sfjs/sfjs'
|
||||
import Storage from '../lib/sfjs/storageManager'
|
||||
import Auth from '../lib/authManager'
|
||||
import Auth from '../lib/sfjs/authManager'
|
||||
import KeysManager from '../lib/keysManager'
|
||||
|
||||
import Abstract from "./Abstract"
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import App from '../app'
|
||||
import Sync from '../lib/sfjs/syncManager'
|
||||
import ModelManager from '../lib/sfjs/modelManager'
|
||||
import Auth from '../lib/authManager'
|
||||
import Auth from '../lib/sfjs/authManager'
|
||||
|
||||
import Abstract from "./Abstract"
|
||||
import ComponentManager from '../lib/componentManager'
|
||||
@@ -220,6 +220,7 @@ export default class Compose extends Abstract {
|
||||
if(!newTags.includes(oldTag)) {
|
||||
oldTag.removeItemAsRelationship(note);
|
||||
oldTag.setDirty(true);
|
||||
// Notes don't have tags as relationships anymore, but we'll keep this to clean up old notes.
|
||||
note.removeItemAsRelationship(oldTag);
|
||||
}
|
||||
}
|
||||
@@ -254,7 +255,6 @@ export default class Compose extends Abstract {
|
||||
this.note.initUUID().then(() => {
|
||||
if(this.props.selectedTagId) {
|
||||
var tag = ModelManager.get().findItem(this.props.selectedTagId);
|
||||
this.note.addItemAsRelationship(tag);
|
||||
tag.addItemAsRelationship(this.note);
|
||||
}
|
||||
this.save();
|
||||
@@ -298,7 +298,7 @@ export default class Compose extends Abstract {
|
||||
if(this.statusTimeout) clearTimeout(this.statusTimeout);
|
||||
this.statusTimeout = setTimeout(function(){
|
||||
var status = "All changes saved"
|
||||
if(Auth.getInstance().offline()) {
|
||||
if(Auth.get().offline()) {
|
||||
status += " (offline)";
|
||||
}
|
||||
this.saveError = false;
|
||||
@@ -316,25 +316,6 @@ export default class Compose extends Abstract {
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
setNavBarSubtitle(title) {
|
||||
if(!this.visible || !this.willBeVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.navigator.setSubTitle({
|
||||
subtitle: title
|
||||
});
|
||||
|
||||
if(!this.didSetNavBarStyle) {
|
||||
this.didSetNavBarStyle = true;
|
||||
var color = GlobalStyles.constantForKey(App.isIOS ? "mainTextColor" : "navBarTextColor");
|
||||
this.props.navigator.setStyle({
|
||||
navBarSubtitleColor: GlobalStyles.hexToRGBA(color, 0.5),
|
||||
navBarSubtitleFontSize: 12
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.state.lockContent) {
|
||||
return (<LockedView />);
|
||||
|
||||
@@ -7,7 +7,7 @@ import Storage from '../lib/sfjs/storageManager'
|
||||
import Sync from '../lib/sfjs/syncManager'
|
||||
import AlertManager from '../lib/sfjs/alertManager'
|
||||
|
||||
import Auth from '../lib/authManager'
|
||||
import Auth from '../lib/sfjs/authManager'
|
||||
import KeysManager from '../lib/keysManager'
|
||||
import Keychain from "../lib/keychain"
|
||||
|
||||
@@ -82,7 +82,7 @@ export default class Notes extends Abstract {
|
||||
Sync.get().removeEventHandler(this.syncObserver);
|
||||
Sync.get().removeSyncStatusObserver(this.syncStatusObserver);
|
||||
|
||||
Auth.getInstance().removeEventObserver(this.signoutObserver);
|
||||
Auth.get().removeEventHandler(this.signoutObserver);
|
||||
if(this.options) {
|
||||
this.options.removeChangeObserver(this.optionsObserver);
|
||||
}
|
||||
@@ -107,7 +107,12 @@ export default class Notes extends Abstract {
|
||||
|
||||
this.syncObserver = Sync.get().addEventHandler((event, data) => {
|
||||
if(event == "sync:completed") {
|
||||
if(_.find(data.retrievedItems, {content_type: "Note"}) || _.find(data.unsavedItems, {content_type: "Note"})) {
|
||||
// We want to reload the list of the retrieved items contains notes or tags.
|
||||
// Since Notes no longer have relationships on tags, if a note's tags change, only the tag will be synced.
|
||||
var retrievedHasNoteOrTag = data.retrievedItems && data.retrievedItems.find((item) => {
|
||||
return ["Note", "Tag"].includes(item.content_type);
|
||||
})
|
||||
if(retrievedHasNoteOrTag || _.find(data.unsavedItems, {content_type: "Note"})) {
|
||||
this.reloadList();
|
||||
}
|
||||
this.mergeState({refreshing: false, loading: false});
|
||||
@@ -137,21 +142,22 @@ export default class Notes extends Abstract {
|
||||
}
|
||||
})
|
||||
|
||||
this.signoutObserver = Auth.getInstance().addEventObserver([Auth.DidSignOutEvent, Auth.WillSignInEvent, Auth.DidSignInEvent], (event) => {
|
||||
if(event == Auth.WillSignInEvent) {
|
||||
this.signoutObserver = Auth.get().addEventHandler((event) => {
|
||||
if(event == SFAuthManager.WillSignInEvent) {
|
||||
this.mergeState({loading: true})
|
||||
} else if(event == Auth.DidSignInEvent) {
|
||||
} else if(event == SFAuthManager.DidSignInEvent) {
|
||||
// Check if there are items that are errorDecrypting and try decrypting with new keys
|
||||
Sync.get().refreshErroredItems().then(() => {
|
||||
this.reloadList();
|
||||
})
|
||||
} else if(event == Auth.DidSignOutEvent) {
|
||||
} else if(event == SFAuthManager.DidSignOutEvent) {
|
||||
this.setStatusBarText(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setStatusBarText(text) {
|
||||
// this.setNavBarSubtitle(text);
|
||||
this.mergeState({showSyncBar: text != null, syncBarText: text});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,21 +104,6 @@ export default class Webview extends Abstract {
|
||||
this.setNavBarSubtitle("Error saving");
|
||||
}
|
||||
|
||||
setNavBarSubtitle(title) {
|
||||
this.props.navigator.setSubTitle({
|
||||
subtitle: title
|
||||
});
|
||||
|
||||
if(!this.didSetNavBarStyle) {
|
||||
this.didSetNavBarStyle = true;
|
||||
var color = GlobalStyles.constantForKey(App.isIOS ? "mainTextColor" : "navBarTextColor");
|
||||
this.props.navigator.setStyle({
|
||||
navBarSubtitleColor: GlobalStyles.hexToRGBA(color, 0.5),
|
||||
navBarSubtitleFontSize: 12
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onNavigatorEvent(event) {
|
||||
super.onNavigatorEvent(event);
|
||||
if (event.type == 'NavBarButtonPress') { // this is the event type for button presses
|
||||
|
||||
Reference in New Issue
Block a user