ScatterDesktop Backup
BackService 调用 saveFile
export default class BackupService {
static async setBackupStrategy(strategy){
const scatter = store.state.scatter.clone();
scatter.settings.autoBackup = strategy;
return store.dispatch(Actions.SET_SCATTER, scatter);
}
static async createBackup(){
const location = getFolderLocation();
if(! location) return false;
await saveFile(location[0]);
}
static async setBackupLocation(){
const location = getFolderLocation();
if(!location) return false;
const scatter = store.state.scatter.clone();
scatter.settings.backupLocation = location[0];
return store.dispatch(Actions.SET_SCATTER, scatter);
}
static async createAutoBackup(){
if(!store.state.scatter || !store.state.scatter.settings) return;
const strategy = store.state.scatter.settings.autoBackup;
if(!strategy || !strategy.length || strategy === BACKUP_STRATEGIES.MANUAL) return;
const backupLocation = store.state.scatter.settings.backupLocation;
if(!backupLocation || !backupLocation.length) return false;
await saveFile(backupLocation);
}
}
写入备份文件
const saveFile = (filepath) => {
return new Promise(resolve => {
const scatter = getLatestScatter();
const date = new Date();
const month = date.getUTCMonth();
const year = date.getUTCFullYear();
const salt = StorageService.getSalt();
const file = scatter + '|SLT|' + salt;
const name = `${filepath}/scatter__${store.state.scatter.hash.substr(0,4)}-${store.state.scatter.hash.slice(-4)}__${store.state.scatter.meta.version}__${month}-${year}.json`;
try {
fs.writeFileSync(name, file, 'utf-8');
resolve(true);
}
catch(e) {
console.error('Error saving file', e);
resolve(false);
}
})
};
备份文件的内容
const scatter = getLatestScatter();
const salt = StorageService.getSalt();
const file = scatter + '|SLT|' + salt;
const getLatestScatter = () => StorageService.getScatter();
StorageService
export default class StorageService {
constructor(){}
static async setScatter(scatter){
return new Promise(async resolve => {
clearSaveTimeouts();
saveResolvers.push(resolve);
safeSetScatter(scatter, resolve);
})
};
static getScatter() {
return scatterStorage().get('scatter');
}
actions
[Actions.SET_SCATTER]:async ({commit, state}, scatter) => {
return new Promise(async resolve => {
const process = Process.savingData();
const seed = await ipcAsync('seed');
const savable = AES.encrypt(scatter.savable(seed), seed);
StorageService.setLocalScatter(savable);
process.updateProgress(50);
StorageService.setScatter(savable).then(() => {
BackupService.createAutoBackup()
});
commit(Actions.SET_SCATTER, scatter);
resolve(scatter);
process.updateProgress(100);
})
},
其中的
const seed = await ipcAsync('seed');
是从
[Actions.SET_SEED]:({commit}, password) => {
return new Promise(async (resolve, reject) => {
const [mnemonic, seed] = await PasswordService.seedPassword(password, true);
resolve(mnemonic);
})
},
static async seedPassword(password, setToState = true){
return new Promise(async (resolve, reject) => {
try {
let seed, mnemonic;
if(password.split(' ').length >= 12) {
seed = await Mnemonic.mnemonicToSeed(password);
mnemonic = password;
} else {
const [m, s] = await Mnemonic.generateMnemonic(password);
seed = s;
mnemonic = m;
}
if(setToState) ipcFaF('seeding', seed);
resolve([mnemonic, seed]);
} catch(e){
resolve([null, null]);
}
})
}
Scatter
https://sourcegraph.com/github.com/GetScatter/ScatterDesktop/-/blob/src/models/Scatter.js#L76:1
savable(seed){
this.keychain.keypairs.map(keypair => keypair.encrypt(seed));
const clone = this.clone();
clone.keychain.identities.map(id => id.encrypt(seed));
// Keychain is always stored encrypted.
clone.encrypt(seed);
return clone;
}
Keychain
static fromJson(json){
let p = Object.assign(this.placeholder(), json);
if(json.hasOwnProperty('keypairs')) p.keypairs = json.keypairs.map(x => Keypair.fromJson(x));
if(json.hasOwnProperty('accounts')) p.accounts = json.accounts.map(x => Account.fromJson(x));
if(json.hasOwnProperty('identities')) p.identities = json.identities.map(x => Identity.fromJson(x));
if(json.hasOwnProperty('permissions')) p.permissions = json.permissions.map(x => Permission.fromJson(x));
if(json.hasOwnProperty('apps')) p.apps = json.apps.map(x => AuthorizedApp.fromJson(x));
return p;
}