Decouple storage, both secure and general.

This commit is contained in:
joshaber 2016-05-31 15:07:53 -04:00
parent ccaf0aa41f
commit 3928ddc72d
5 changed files with 42 additions and 30 deletions

View file

@ -1,5 +1,4 @@
import {shell} from 'electron'
import * as keytar from 'keytar'
import guid from './lib/guid'
import User from './user'
@ -49,16 +48,6 @@ export function askUserToAuth(endpoint: string) {
shell.openExternal(getOAuthURL(authState))
}
export function getToken(login: string, endpoint: string): string {
const serviceName = getServiceNameForUser(new User(login, endpoint, ''))
return keytar.getPassword(serviceName, login)
}
export function setToken(user: User, token: string) {
const serviceName = getServiceNameForUser(user)
keytar.addPassword(serviceName, user.getLogin(), token)
}
function getServiceNameForUser(user: User): string {
export function getKeyForUser(user: User): string {
return `GitHub ${user.getEndpoint()}`
}

View file

@ -8,6 +8,7 @@ import {requestToken, getDotComEndpoint} from './auth'
import {URLActionType, OAuthAction} from './lib/parse-url'
import UsersStore from './users-store'
import User from './user'
import tokenStore from './token-store'
const Octokat = require('octokat')
@ -27,8 +28,8 @@ const style = {
paddingTop: process.platform === 'darwin' ? 20 : 0
}
const usersStore = new UsersStore()
usersStore.loadFromDisk()
const usersStore = new UsersStore(localStorage, tokenStore)
usersStore.loadFromStore()
ReactDOM.render(<App style={style} usersStore={usersStore}/>, document.getElementById('content'))

9
src/stores.ts Normal file
View file

@ -0,0 +1,9 @@
export interface SecureStore {
setItem(key: string, login: string, value: string): void
getItem(key: string, login: string): string
}
export interface DataStore {
setItem(key: string, value: string): void
getItem(key: string): string
}

11
src/token-store.ts Normal file
View file

@ -0,0 +1,11 @@
import * as keytar from 'keytar'
export default {
setItem: function (key: string, login: string, value: string) {
keytar.addPassword(key, login, value)
},
getItem: function (key: string, login: string): string {
return keytar.getPassword(key, login)
}
}

View file

@ -1,18 +1,21 @@
import {Emitter, Disposable} from 'event-kit'
import {setToken, getToken} from './auth'
import {DataStore, SecureStore} from './stores'
import {getKeyForUser} from './auth'
import User from './user'
export default class UsersStore {
private dataStore: DataStore
private secureStore: SecureStore
private emitter: Emitter
private users: User[]
private persisted: boolean
public constructor() {
public constructor(dataStore: DataStore, secureStore: SecureStore) {
this.dataStore = dataStore
this.secureStore = secureStore
this.emitter = new Emitter()
this.users = []
this.persisted = false
}
public onUsersChanged(fn: (users: User[]) => void): Disposable {
@ -28,33 +31,32 @@ export default class UsersStore {
}
public addUser(user: User) {
setToken(user, user.getToken())
this.secureStore.setItem(getKeyForUser(user), user.getLogin(), user.getToken())
this.users.push(user)
this.usersDidChange()
if (this.persisted) {
this.saveToDisk()
}
this.save()
}
public loadFromDisk() {
this.persisted = true
const raw = localStorage.getItem('users')
public loadFromStore() {
const raw = this.dataStore.getItem('users')
if (!raw || !raw.length) {
return
}
const rawUsers: any[] = JSON.parse(raw)
const usersWithTokens = rawUsers.map(user => new User(user.login, user.endpoint, getToken(user.login, user.endpoint)))
const usersWithTokens = rawUsers.map(user => {
const userWithoutToken = new User(user.login, user.endpoint, '')
return userWithoutToken.userWithToken(this.secureStore.getItem(getKeyForUser(userWithoutToken), user.login))
})
this.users = usersWithTokens
this.usersDidChange()
}
private saveToDisk() {
private save() {
const usersWithoutTokens = this.users.map(user => user.userWithToken(''))
localStorage.setItem('users', JSON.stringify(usersWithoutTokens))
this.dataStore.setItem('users', JSON.stringify(usersWithoutTokens))
}
}