diff --git a/src/App.tsx b/src/App.tsx index e893392..a1e8604 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -152,7 +152,7 @@ const AppBarWitHistory = withRouter( private goBack() { this.props.history!.goBack(); } - }, + } ); const IconRefreshWithSpin = withSpin(NavigationRefresh); @@ -249,7 +249,7 @@ const credentialsSelector = createSelector( encryptionKey, }, }; - }, + } ); const mapStateToProps = (state: store.StoreState) => { @@ -261,5 +261,5 @@ const mapStateToProps = (state: store.StoreState) => { }; export default connect( - mapStateToProps, + mapStateToProps )(App); diff --git a/src/Journals/Journal.tsx b/src/Journals/Journal.tsx index 823dc71..94e69fb 100644 --- a/src/Journals/Journal.tsx +++ b/src/Journals/Journal.tsx @@ -43,7 +43,7 @@ const JournalCalendar = journalView(PersistCalendar, Event); const JournalTaskList = journalView(TaskList, Event); class Journal extends React.Component { - state: { + public state: { tab: number, }; @@ -55,7 +55,7 @@ class Journal extends React.Component { }; } - render() { + public render() { const { theme, isOwner, syncJournal } = this.props; let currentTab = this.state.tab; let journalOnly = false; diff --git a/src/Journals/JournalEdit.tsx b/src/Journals/JournalEdit.tsx index b5582df..7c89dd5 100644 --- a/src/Journals/JournalEdit.tsx +++ b/src/Journals/JournalEdit.tsx @@ -32,7 +32,7 @@ interface PropsTypeInner extends PropsType { } class JournalEdit extends React.PureComponent { - state = { + public state = { info: { uid: '', type: '', @@ -61,7 +61,7 @@ class JournalEdit extends React.PureComponent { } } - render() { + public render() { const { item, onDelete, onCancel } = this.props; const pageTitle = (item !== undefined) ? item.displayName : 'New Journal'; @@ -177,7 +177,7 @@ class JournalEdit extends React.PureComponent { private onDeleteRequest() { this.setState({ - showDeleteDialog: true + showDeleteDialog: true, }); } diff --git a/src/Journals/JournalMembers.tsx b/src/Journals/JournalMembers.tsx index 1a8ba47..fb8f280 100644 --- a/src/Journals/JournalMembers.tsx +++ b/src/Journals/JournalMembers.tsx @@ -21,7 +21,7 @@ interface PropsTypeInner extends PropsType { } class JournalMembers extends React.PureComponent { - state = { + public state = { members: null as EteSync.JournalMemberJson[] | null, }; @@ -29,7 +29,7 @@ class JournalMembers extends React.PureComponent { super(props); } - render() { + public render() { const { info } = this.props; const { members } = this.state; @@ -57,7 +57,7 @@ class JournalMembers extends React.PureComponent { ); } - componentDidMount() { + public componentDidMount() { this.fetchMembers(); } diff --git a/src/Journals/JournalsList.tsx b/src/Journals/JournalsList.tsx index 9135904..7bd103c 100644 --- a/src/Journals/JournalsList.tsx +++ b/src/Journals/JournalsList.tsx @@ -18,7 +18,7 @@ import { routeResolver } from '../App'; import { JournalsData, UserInfoData, CredentialsData } from '../store'; class JournalsList extends React.PureComponent { - props: { + public props: { etesync: CredentialsData; journals: JournalsData; userInfo: UserInfoData; @@ -30,7 +30,7 @@ class JournalsList extends React.PureComponent { this.journalClicked = this.journalClicked.bind(this); } - render() { + public render() { const derived = this.props.etesync.encryptionKey; let asymmetricCryptoManager: EteSync.AsymmetricCryptoManager; const journalMap = this.props.journals.reduce( @@ -47,7 +47,7 @@ class JournalsList extends React.PureComponent { } else { cryptoManager = new EteSync.CryptoManager(derived, journal.uid, journal.version); } - let info = journal.getInfo(cryptoManager); + const info = journal.getInfo(cryptoManager); ret[info.type] = ret[info.type] || []; ret[info.type].push( this.journalClicked(journal.uid)}> @@ -59,7 +59,7 @@ class JournalsList extends React.PureComponent { }, { CALENDAR: [], ADDRESS_BOOK: [], - TASKS: [] + TASKS: [], }); return ( @@ -94,7 +94,7 @@ class JournalsList extends React.PureComponent { } private journalClicked(journalUid: string) { - this.props.history.push(routeResolver.getRoute('journals._id', { journalUid: journalUid })); + this.props.history.push(routeResolver.getRoute('journals._id', { journalUid })); } } diff --git a/src/Journals/index.tsx b/src/Journals/index.tsx index b3d177b..7ef2ec7 100644 --- a/src/Journals/index.tsx +++ b/src/Journals/index.tsx @@ -16,7 +16,7 @@ import { SyncInfo } from '../SyncGate'; import * as EteSync from '../api/EteSync'; class Journals extends React.PureComponent { - props: { + public props: { etesync: CredentialsData; journals: JournalsData; userInfo: UserInfoData; @@ -32,7 +32,7 @@ class Journals extends React.PureComponent { this.onItemSave = this.onItemSave.bind(this); } - render() { + public render() { return ( diff --git a/src/LoginGate.tsx b/src/LoginGate.tsx index e851d59..53fbd29 100644 --- a/src/LoginGate.tsx +++ b/src/LoginGate.tsx @@ -11,10 +11,10 @@ import { login, deriveKey } from './store/actions'; import * as C from './constants'; -const SignedPagesBadge = require('./images/signed-pages-badge.svg'); +import SignedPagesBadge from './images/signed-pages-badge.svg'; class LoginGate extends React.Component { - props: { + public props: { credentials: CredentialsType; }; @@ -24,16 +24,16 @@ class LoginGate extends React.Component { this.onEncryptionFormSubmit = this.onEncryptionFormSubmit.bind(this); } - onFormSubmit(username: string, password: string, encryptionPassword: string, serviceApiUrl?: string) { + public onFormSubmit(username: string, password: string, encryptionPassword: string, serviceApiUrl?: string) { serviceApiUrl = serviceApiUrl ? serviceApiUrl : C.serviceApiBase; store.dispatch(login(username, password, encryptionPassword, serviceApiUrl)); } - onEncryptionFormSubmit(encryptionPassword: string) { + public onEncryptionFormSubmit(encryptionPassword: string) { store.dispatch(deriveKey(this.props.credentials.value!.credentials.email, encryptionPassword)); } - render() { + public render() { if (this.props.credentials.value === null) { const style = { isSafe: { @@ -43,7 +43,7 @@ class LoginGate extends React.Component { divider: { margin: '30px 0', color: '#00000025', - } + }, }; return ( diff --git a/src/Pim/PimMain.tsx b/src/Pim/PimMain.tsx index 9b26e4e..2f75a1b 100644 --- a/src/Pim/PimMain.tsx +++ b/src/Pim/PimMain.tsx @@ -28,16 +28,16 @@ const tasksTitle = 'Tasks'; const PersistCalendar = historyPersistor('Calendar')(Calendar); interface PropsType { - contacts: Array; - events: Array; - tasks: Array; + contacts: ContactType[]; + events: EventType[]; + tasks: TaskType[]; location?: Location; history?: History; theme: Theme; } class PimMain extends React.PureComponent { - state: { + public state: { tab: number; }; @@ -51,35 +51,35 @@ class PimMain extends React.PureComponent { this.newEvent = this.newEvent.bind(this); } - eventClicked(event: ICAL.Event) { + public eventClicked(event: ICAL.Event) { const uid = event.uid; this.props.history!.push( routeResolver.getRoute('pim.events._id', { itemUid: uid })); } - taskClicked(event: ICAL.Event) { + public taskClicked(event: ICAL.Event) { const uid = event.uid; this.props.history!.push( routeResolver.getRoute('pim.tasks._id', { itemUid: uid })); } - contactClicked(contact: ContactType) { + public contactClicked(contact: ContactType) { const uid = contact.uid; this.props.history!.push( routeResolver.getRoute('pim.contacts._id', { itemUid: uid })); } - newEvent(start?: Date, end?: Date) { + public newEvent(start?: Date, end?: Date) { this.props.history!.push( routeResolver.getRoute('pim.events.new'), {start, end} ); } - floatingButtonClicked() { + public floatingButtonClicked() { if (this.state.tab === 0) { this.props.history!.push( routeResolver.getRoute('pim.contacts.new') @@ -93,7 +93,7 @@ class PimMain extends React.PureComponent { } } - render() { + public render() { const { theme } = this.props; const { tab } = this.state; const style = { diff --git a/src/Pim/index.tsx b/src/Pim/index.tsx index d5fb042..4ded54b 100644 --- a/src/Pim/index.tsx +++ b/src/Pim/index.tsx @@ -47,9 +47,9 @@ function objValues(obj: any) { const itemsSelector = createSelector( (props: {syncInfo: SyncInfo}) => props.syncInfo, (syncInfo) => { - let collectionsAddressBook: Array = []; - let collectionsCalendar: Array = []; - let collectionsTaskList: Array = []; + const collectionsAddressBook: EteSync.CollectionInfo[] = []; + const collectionsCalendar: EteSync.CollectionInfo[] = []; + const collectionsTaskList: EteSync.CollectionInfo[] = []; let addressBookItems: {[key: string]: ContactType} = {}; let calendarItems: {[key: string]: EventType} = {}; let taskListItems: {[key: string]: TaskType} = {}; @@ -73,9 +73,9 @@ const itemsSelector = createSelector( ); return { - collectionsAddressBook, collectionsCalendar, collectionsTaskList, addressBookItems, calendarItems, taskListItems + collectionsAddressBook, collectionsCalendar, collectionsTaskList, addressBookItems, calendarItems, taskListItems, }; - }, + } ); const ItemChangeLog = pure((props: any) => { @@ -102,7 +102,7 @@ const ItemChangeLog = pure((props: any) => { type CollectionRoutesPropsType = RouteComponentProps<{}> & { syncInfo: SyncInfo, routePrefix: string, - collections: Array, + collections: EteSync.CollectionInfo[], componentEdit: any, componentView: any, items: {[key: string]: PimType}, @@ -123,7 +123,7 @@ const styles = (theme: any) => ({ const CollectionRoutes = withStyles(styles)(withRouter( class CollectionRoutesInner extends React.PureComponent { - render() { + public render() { const props = this.props; const { classes } = this.props; const ComponentEdit = props.componentEdit; @@ -221,7 +221,7 @@ const CollectionRoutes = withStyles(styles)(withRouter( )); class Pim extends React.PureComponent { - props: { + public props: { etesync: CredentialsData; userInfo: UserInfoData; syncInfo: SyncInfo; @@ -235,7 +235,7 @@ class Pim extends React.PureComponent { this.onItemSave = this.onItemSave.bind(this); } - onItemSave(item: PimType, journalUid: string, originalEvent?: PimType) { + public onItemSave(item: PimType, journalUid: string, originalEvent?: PimType) { const syncJournal = this.props.syncInfo.get(journalUid); if (syncJournal === undefined) { @@ -244,7 +244,7 @@ class Pim extends React.PureComponent { const journal = syncJournal.journal; - let action = (originalEvent === undefined) ? EteSync.SyncEntryAction.Add : EteSync.SyncEntryAction.Change; + const action = (originalEvent === undefined) ? EteSync.SyncEntryAction.Add : EteSync.SyncEntryAction.Change; let prevUid: string | null = null; let last = syncJournal.journalEntries.last() as EteSync.Entry; @@ -270,7 +270,7 @@ class Pim extends React.PureComponent { }); } - onItemDelete(item: PimType, journalUid: string) { + public onItemDelete(item: PimType, journalUid: string) { const syncJournal = this.props.syncInfo.get(journalUid); if (syncJournal === undefined) { @@ -279,7 +279,7 @@ class Pim extends React.PureComponent { const journal = syncJournal.journal; - let action = EteSync.SyncEntryAction.Delete; + const action = EteSync.SyncEntryAction.Delete; let prevUid: string | null = null; let last = syncJournal.journalEntries.last() as EteSync.Entry; @@ -305,11 +305,11 @@ class Pim extends React.PureComponent { }); } - onCancel() { + public onCancel() { this.props.history.goBack(); } - render() { + public render() { const { collectionsAddressBook, collectionsCalendar, collectionsTaskList, addressBookItems, calendarItems, taskListItems } = itemsSelector(this.props); return ( diff --git a/src/Settings/index.tsx b/src/Settings/index.tsx index 0251522..3d59a9c 100644 --- a/src/Settings/index.tsx +++ b/src/Settings/index.tsx @@ -28,15 +28,7 @@ class Settings extends React.PureComponent { this.handleChange = this.handleChange.bind(this); } - private handleChange(event: React.ChangeEvent) { - const name = event.target.name; - const value = event.target.value; - - const { settings } = this.props; - store.dispatch(setSettings({ ...settings, [name]: value})); - } - - render() { + public render() { const { settings } = this.props; return ( <> @@ -61,9 +53,17 @@ class Settings extends React.PureComponent { ); } - onCancel() { + public onCancel() { this.props.history.goBack(); } + + private handleChange(event: React.ChangeEvent) { + const name = event.target.name; + const value = event.target.value; + + const { settings } = this.props; + store.dispatch(setSettings({ ...settings, [name]: value})); + } } const mapStateToProps = (state: StoreState, props: PropsType) => { diff --git a/src/SideMenu/index.tsx b/src/SideMenu/index.tsx index 24c0280..6472ba6 100644 --- a/src/SideMenu/index.tsx +++ b/src/SideMenu/index.tsx @@ -11,7 +11,7 @@ import ActionBugReport from '@material-ui/icons/BugReport'; import ActionQuestionAnswer from '@material-ui/icons/QuestionAnswer'; import LogoutIcon from '@material-ui/icons/PowerSettingsNew'; -const logo = require('../images/logo.svg'); +import logo from '../images/logo.svg'; import { routeResolver } from '../App'; @@ -37,12 +37,12 @@ class SideMenu extends React.PureComponent { this.logout = this.logout.bind(this); } - logout() { + public logout() { store.dispatch(logout()); this.props.onCloseDrawerRequest(); } - render() { + public render() { const { theme } = this.props; const username = (this.props.etesync && this.props.etesync.credentials.email) ? this.props.etesync.credentials.email diff --git a/src/SyncGate.tsx b/src/SyncGate.tsx index 288a42e..80ebca4 100644 --- a/src/SyncGate.tsx +++ b/src/SyncGate.tsx @@ -78,7 +78,7 @@ const syncInfoSelector = createSelector( const collectionInfo = journal.getInfo(cryptoManager); const syncEntries = journalEntries.value.map((entry: EteSync.Entry) => { - let syncEntry = entry.getSyncEntry(cryptoManager, prevUid); + const syncEntry = entry.getSyncEntry(cryptoManager, prevUid); prevUid = entry.uid; return syncEntry; @@ -93,7 +93,7 @@ const syncInfoSelector = createSelector( }, Map() ); - }, + } ); const PimRouter = withRouter(Pim); @@ -103,7 +103,7 @@ class SyncGate extends React.PureComponent { super(props); } - componentDidMount() { + public componentDidMount() { const me = this.props.etesync.credentials.email; const syncAll = () => { store.dispatch(fetchAll(this.props.etesync, this.props.entries)).then((haveJournals: boolean) => { @@ -153,7 +153,7 @@ class SyncGate extends React.PureComponent { } } - render() { + public render() { const entryArrays = this.props.entries; const journals = this.props.journals.value; @@ -162,7 +162,7 @@ class SyncGate extends React.PureComponent { } else if (this.props.journals.error) { return ; } else { - let errors: Array<{journal: string, error: Error}> = []; + const errors: Array<{journal: string, error: Error}> = []; this.props.entries.forEach((entry, journal) => { if (entry.error) { errors.push({journal, error: entry.error}); diff --git a/src/api/Crypto.ts b/src/api/Crypto.ts index 18a4d62..0fb80bc 100644 --- a/src/api/Crypto.ts +++ b/src/api/Crypto.ts @@ -11,8 +11,8 @@ sjcl.random.startCollectors(); export const HMAC_SIZE_BYTES = 32; export class AsymmetricKeyPair { - publicKey: byte[]; - privateKey: byte[]; + public publicKey: byte[]; + public privateKey: byte[]; constructor(publicKey: byte[], privateKey: byte[]) { this.publicKey = publicKey; @@ -32,29 +32,29 @@ export function genUid() { } function hmac256(salt: sjcl.BitArray, key: sjcl.BitArray) { - let hmac = new sjcl.misc.hmac(salt); + const hmac = new sjcl.misc.hmac(salt); return hmac.encrypt(key); } export class CryptoManager { - version: number; - key: sjcl.BitArray; - cipherKey: sjcl.BitArray; - hmacKey: sjcl.BitArray; - cipherWords = 4; - - static fromDerivedKey(key: byte[], version: number = Constants.CURRENT_VERSION) { + public static fromDerivedKey(key: byte[], version: number = Constants.CURRENT_VERSION) { // FIXME: Cleanup this hack const ret = new CryptoManager('', '', version); ret.key = sjcl.codec.bytes.toBits(key); ret._updateDerivedKeys(); return ret; } + public version: number; + public key: sjcl.BitArray; + public cipherKey: sjcl.BitArray; + public hmacKey: sjcl.BitArray; + + public cipherWords = 4; constructor(_keyBase64: base64, salt: string, version: number = Constants.CURRENT_VERSION) { this.version = version; - let key = sjcl.codec.base64.toBits(_keyBase64); + const key = sjcl.codec.base64.toBits(_keyBase64); // FIXME: Clean up all exeptions if (version > Constants.CURRENT_VERSION) { throw new Error('VersionTooNewException'); @@ -67,53 +67,53 @@ export class CryptoManager { this._updateDerivedKeys(); } - _updateDerivedKeys() { + public _updateDerivedKeys() { this.cipherKey = hmac256(sjcl.codec.utf8String.toBits('aes'), this.key); this.hmacKey = hmac256(sjcl.codec.utf8String.toBits('hmac'), this.key); } - encryptBits(content: sjcl.BitArray): byte[] { + public encryptBits(content: sjcl.BitArray): byte[] { const iv = sjcl.random.randomWords(this.cipherWords); - let prp = new sjcl.cipher.aes(this.cipherKey); - let cipherText = sjcl.mode.cbc.encrypt(prp, content, iv); + const prp = new sjcl.cipher.aes(this.cipherKey); + const cipherText = sjcl.mode.cbc.encrypt(prp, content, iv); return sjcl.codec.bytes.fromBits(iv.concat(cipherText)); } - decryptBits(content: byte[]): sjcl.BitArray { - let cipherText = sjcl.codec.bytes.toBits(content); + public decryptBits(content: byte[]): sjcl.BitArray { + const cipherText = sjcl.codec.bytes.toBits(content); const iv = cipherText.splice(0, this.cipherWords); - let prp = new sjcl.cipher.aes(this.cipherKey); - let clearText = sjcl.mode.cbc.decrypt(prp, cipherText, iv); + const prp = new sjcl.cipher.aes(this.cipherKey); + const clearText = sjcl.mode.cbc.decrypt(prp, cipherText, iv); return clearText; } - encryptBytes(content: byte[]): byte[] { + public encryptBytes(content: byte[]): byte[] { return this.encryptBits(sjcl.codec.bytes.toBits(content)); } - decryptBytes(content: byte[]): byte[] { + public decryptBytes(content: byte[]): byte[] { return sjcl.codec.bytes.fromBits(this.decryptBits(content)); } - encrypt(content: string): byte[] { + public encrypt(content: string): byte[] { return this.encryptBits(sjcl.codec.utf8String.toBits(content)); } - decrypt(content: byte[]): string { + public decrypt(content: byte[]): string { return sjcl.codec.utf8String.fromBits(this.decryptBits(content)); } - hmac(content: byte[]): byte[] { + public hmac(content: byte[]): byte[] { return sjcl.codec.bytes.fromBits(this.hmacBase(content)); } - hmac64(content: byte[]): base64 { + public hmac64(content: byte[]): base64 { return sjcl.codec.base64.fromBits(this.hmacBase(content)); } - hmacHex(content: byte[]): string { + public hmacHex(content: byte[]): string { return sjcl.codec.hex.fromBits(this.hmacBase(content)); } @@ -134,9 +134,8 @@ function bufferToArray(buffer: Buffer) { } export class AsymmetricCryptoManager { - keyPair: NodeRSA; - static generateKeyPair() { + public static generateKeyPair() { const keyPair = new NodeRSA(); keyPair.generateKeyPair(3072, 65537); const pubkey = keyPair.exportKey('pkcs8-public-der') as Buffer; @@ -144,19 +143,20 @@ export class AsymmetricCryptoManager { return new AsymmetricKeyPair( bufferToArray(pubkey), bufferToArray(privkey)); } + public keyPair: NodeRSA; constructor(keyPair: AsymmetricKeyPair) { this.keyPair = new NodeRSA(); this.keyPair.importKey(Buffer.from(keyPair.privateKey), 'pkcs8-der'); } - encryptBytes(publicKey: byte[], content: byte[]): byte[] { + public encryptBytes(publicKey: byte[], content: byte[]): byte[] { const key = new NodeRSA(); key.importKey(Buffer.from(publicKey), 'pkcs8-public-der'); return bufferToArray(key.encrypt(Buffer.from(content), 'buffer')); } - decryptBytes(content: byte[]): byte[] { + public decryptBytes(content: byte[]): byte[] { return bufferToArray(this.keyPair.decrypt(Buffer.from(content), 'buffer')); } } diff --git a/src/api/EteSync.test.ts b/src/api/EteSync.test.ts index 92308ab..311e32a 100644 --- a/src/api/EteSync.test.ts +++ b/src/api/EteSync.test.ts @@ -9,26 +9,26 @@ import { USER, PASSWORD, keyBase64 } from './TestConstants'; let credentials: EteSync.Credentials; beforeEach(async () => { - let authenticator = new EteSync.Authenticator(testApiBase); + const authenticator = new EteSync.Authenticator(testApiBase); const authToken = await authenticator.getAuthToken(USER, PASSWORD); credentials = new EteSync.Credentials(USER, authToken); await fetch(testApiBase + '/reset/', { method: 'post', - headers: { 'Authorization': 'Token ' + credentials.authToken }, + headers: { Authorization: 'Token ' + credentials.authToken }, }); }); it('Simple sync', async () => { - let journalManager = new EteSync.JournalManager(credentials, testApiBase); + const journalManager = new EteSync.JournalManager(credentials, testApiBase); let journals = await journalManager.list(); expect(journals.length).toBe(0); const uid1 = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash('id1')); const cryptoManager = new EteSync.CryptoManager(keyBase64, USER); const info1 = new EteSync.CollectionInfo({uid: uid1, content: 'test', displayName: 'Dislpay 1'}); - let journal = new EteSync.Journal(); + const journal = new EteSync.Journal(); journal.setInfo(cryptoManager, info1); await expect(journalManager.create(journal)).resolves.toBeDefined(); @@ -41,7 +41,7 @@ it('Simple sync', async () => { expect(journals[0].uid).toBe(journal.uid); // Update - let info2 = new EteSync.CollectionInfo(info1); + const info2 = new EteSync.CollectionInfo(info1); info2.displayName = 'Display 2'; journal.setInfo(cryptoManager, info2); @@ -59,24 +59,24 @@ it('Simple sync', async () => { }); it('Journal Entry sync', async () => { - let journalManager = new EteSync.JournalManager(credentials, testApiBase); + const journalManager = new EteSync.JournalManager(credentials, testApiBase); const uid1 = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash('id1')); const cryptoManager = new EteSync.CryptoManager(keyBase64, USER); const info1 = new EteSync.CollectionInfo({uid: uid1, content: 'test', displayName: 'Dislpay 1'}); - let journal = new EteSync.Journal(); + const journal = new EteSync.Journal(); journal.setInfo(cryptoManager, info1); await expect(journalManager.create(journal)).resolves.toBeDefined(); - let entryManager = new EteSync.EntryManager(credentials, testApiBase, journal.uid); + const entryManager = new EteSync.EntryManager(credentials, testApiBase, journal.uid); let entries = await entryManager.list(null); expect(entries.length).toBe(0); const syncEntry = new EteSync.SyncEntry({action: 'ADD', content: 'bla'}); let prevUid = null; - let entry = new EteSync.Entry(); + const entry = new EteSync.Entry(); entry.setSyncEntry(cryptoManager, syncEntry, prevUid); entries = [entry]; @@ -120,7 +120,7 @@ it('Journal Entry sync', async () => { expect(() => { let prev = null; - for (let ent of entries) { + for (const ent of entries) { expect(ent.getSyncEntry(cryptoManager, prev)).toBeDefined(); prev = ent.uid; } @@ -135,7 +135,7 @@ it('User info sync', async () => { await expect(userInfoManager.fetch(USER)).rejects.toBeInstanceOf(EteSync.HTTPError); // Create - let userInfo = new EteSync.UserInfo(USER); + const userInfo = new EteSync.UserInfo(USER); userInfo.setKeyPair(cryptoManager, new EteSync.AsymmetricKeyPair([0, 1, 2, 3], [4, 5, 6, 6])); await expect(userInfoManager.create(userInfo)).resolves.not.toBeNull(); diff --git a/src/api/EteSync.ts b/src/api/EteSync.ts index 93e0141..9663a8d 100644 --- a/src/api/EteSync.ts +++ b/src/api/EteSync.ts @@ -42,8 +42,8 @@ function hmacToHex(hmac: byte[]): string { } export class Credentials { - email: string; - authToken: string; + public email: string; + public authToken: string; constructor(email: string, authToken: string) { this.email = email; @@ -52,11 +52,11 @@ export class Credentials { } export class CollectionInfo { - uid: string; - type: string; - displayName: string; - description: string; - color: number; + public uid: string; + public type: string; + public displayName: string; + public description: string; + public color: number; constructor(json?: any) { CastJson(json, this); @@ -76,13 +76,13 @@ class BaseItem { this._json = {} as any; } - deserialize(json: T) { + public deserialize(json: T) { this._json = Object.assign({}, json); this._encrypted = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(json.content)); this._content = undefined; } - serialize(): T { + public serialize(): T { return Object.assign( {}, this._json, @@ -140,33 +140,33 @@ export class Journal extends BaseJournal { return this._json.version; } - setInfo(cryptoManager: CryptoManager, info: CollectionInfo) { + public setInfo(cryptoManager: CryptoManager, info: CollectionInfo) { this._json.uid = info.uid; this._content = info; const encrypted = cryptoManager.encrypt(JSON.stringify(this._content)); this._encrypted = this.calculateHmac(cryptoManager, encrypted).concat(encrypted); } - getInfo(cryptoManager: CryptoManager): CollectionInfo { + public getInfo(cryptoManager: CryptoManager): CollectionInfo { this.verify(cryptoManager); if (this._content === undefined) { this._content = JSON.parse(cryptoManager.decrypt(this.encryptedContent())); } - let ret = new CollectionInfo(this._content); + const ret = new CollectionInfo(this._content); ret.uid = this.uid; return ret; } - calculateHmac(cryptoManager: CryptoManager, encrypted: byte[]): byte[] { - let prefix = stringToByteArray(this.uid); + public calculateHmac(cryptoManager: CryptoManager, encrypted: byte[]): byte[] { + const prefix = stringToByteArray(this.uid); return cryptoManager.hmac(prefix.concat(encrypted)); } - verify(cryptoManager: CryptoManager) { - let calculated = this.calculateHmac(cryptoManager, this.encryptedContent()); - let hmac = this._encrypted.slice(0, HMAC_SIZE_BYTES); + public verify(cryptoManager: CryptoManager) { + const calculated = this.calculateHmac(cryptoManager, this.encryptedContent()); + const hmac = this._encrypted.slice(0, HMAC_SIZE_BYTES); super.verifyBase(hmac, calculated); } @@ -183,9 +183,9 @@ export enum SyncEntryAction { } export class SyncEntry { - uid?: string; - action: SyncEntryAction; - content: string; + public uid?: string; + public action: SyncEntryAction; + public content: string; constructor(json?: any, uid?: string) { CastJson(json, this); @@ -193,17 +193,16 @@ export class SyncEntry { } } -export interface EntryJson extends BaseJson { -} +export type EntryJson = BaseJson; export class Entry extends BaseJournal { - setSyncEntry(cryptoManager: CryptoManager, info: SyncEntry, prevUid: string | null) { + public setSyncEntry(cryptoManager: CryptoManager, info: SyncEntry, prevUid: string | null) { this._content = info; this._encrypted = cryptoManager.encrypt(JSON.stringify(this._content)); this._json.uid = hmacToHex(this.calculateHmac(cryptoManager, this._encrypted, prevUid)); } - getSyncEntry(cryptoManager: CryptoManager, prevUid: string | null): SyncEntry { + public getSyncEntry(cryptoManager: CryptoManager, prevUid: string | null): SyncEntry { this.verify(cryptoManager, prevUid); if (this._content === undefined) { @@ -213,15 +212,15 @@ export class Entry extends BaseJournal { return new SyncEntry(this._content, this.uid); } - verify(cryptoManager: CryptoManager, prevUid: string | null) { - let calculated = this.calculateHmac(cryptoManager, this._encrypted, prevUid); - let hmac = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(this.uid)); + public verify(cryptoManager: CryptoManager, prevUid: string | null) { + const calculated = this.calculateHmac(cryptoManager, this._encrypted, prevUid); + const hmac = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(this.uid)); super.verifyBase(hmac, calculated); } private calculateHmac(cryptoManager: CryptoManager, encrypted: byte[], prevUid: string | null): byte[] { - let prefix = (prevUid !== null) ? stringToByteArray(prevUid) : []; + const prefix = (prevUid !== null) ? stringToByteArray(prevUid) : []; return cryptoManager.hmac(prefix.concat(encrypted)); } } @@ -233,7 +232,7 @@ export interface UserInfoJson extends BaseItemJson { } export class UserInfo extends BaseItem { - _owner: string; + public _owner: string; constructor(owner: string, version: number = Constants.CURRENT_VERSION) { super(); @@ -253,20 +252,20 @@ export class UserInfo extends BaseItem { return this._json.pubkey; } - serialize(): UserInfoJson { - let ret = super.serialize(); + public serialize(): UserInfoJson { + const ret = super.serialize(); ret.owner = this._owner; return ret; } - setKeyPair(cryptoManager: CryptoManager, keyPair: AsymmetricKeyPair) { + public setKeyPair(cryptoManager: CryptoManager, keyPair: AsymmetricKeyPair) { this._json.pubkey = sjcl.codec.base64.fromBits(sjcl.codec.bytes.toBits(keyPair.publicKey)); this._content = keyPair.privateKey; const encrypted = cryptoManager.encryptBytes(keyPair.privateKey); this._encrypted = this.calculateHmac(cryptoManager, encrypted).concat(encrypted); } - getKeyPair(cryptoManager: CryptoManager): AsymmetricKeyPair { + public getKeyPair(cryptoManager: CryptoManager): AsymmetricKeyPair { this.verify(cryptoManager); if (this._content === undefined) { @@ -277,14 +276,14 @@ export class UserInfo extends BaseItem { return new AsymmetricKeyPair(pubkey, this._content as byte[]); } - calculateHmac(cryptoManager: CryptoManager, encrypted: byte[]): byte[] { - let postfix = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(this._json.pubkey)); + public calculateHmac(cryptoManager: CryptoManager, encrypted: byte[]): byte[] { + const postfix = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(this._json.pubkey)); return cryptoManager.hmac(encrypted.concat(postfix)); } - verify(cryptoManager: CryptoManager) { - let calculated = this.calculateHmac(cryptoManager, this.encryptedContent()); - let hmac = this._encrypted.slice(0, HMAC_SIZE_BYTES); + public verify(cryptoManager: CryptoManager) { + const calculated = this.calculateHmac(cryptoManager, this.encryptedContent()); + const hmac = this._encrypted.slice(0, HMAC_SIZE_BYTES); super.verifyBase(hmac, calculated); } @@ -297,9 +296,8 @@ export class UserInfo extends BaseItem { // FIXME: baseUrl and apiBase should be the right type all around. class BaseNetwork { - apiBase: any; // FIXME - static urlExtend(_baseUrl: URL, segments: Array): URL { + public static urlExtend(_baseUrl: URL, segments: string[]): URL { let baseUrl = _baseUrl as any; baseUrl = baseUrl.clone(); for (const segment of segments) { @@ -307,18 +305,19 @@ class BaseNetwork { } return baseUrl.normalize(); } + public apiBase: any; // FIXME constructor(apiBase: string) { this.apiBase = URI(apiBase).normalize(); } // FIXME: Get the correct type for extra - newCall(segments: Array = [], extra: any = {}, _apiBase: URL = this.apiBase): Promise<{} | Array> { - let apiBase = BaseNetwork.urlExtend(_apiBase, segments); + public newCall(segments: string[] = [], extra: any = {}, _apiBase: URL = this.apiBase): Promise<{} | any[]> { + const apiBase = BaseNetwork.urlExtend(_apiBase, segments); extra = Object.assign({}, extra); extra.headers = Object.assign( - { 'Accept': 'application/json' }, + { Accept: 'application/json' }, extra.headers); return new Promise((resolve, reject) => { @@ -358,17 +357,17 @@ export class Authenticator extends BaseNetwork { this.apiBase = BaseNetwork.urlExtend(this.apiBase, ['api-token-auth', '']); } - getAuthToken(username: string, password: string): Promise { + public getAuthToken(username: string, password: string): Promise { return new Promise((resolve, reject) => { // FIXME: should be FormData but doesn't work for whatever reason - let form = 'username=' + encodeURIComponent(username) + + const form = 'username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password); const extra = { method: 'post', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', }, - body: form + body: form, }; this.newCall([], extra).then((json: {token: string}) => { @@ -383,19 +382,19 @@ export class Authenticator extends BaseNetwork { export class BaseManager extends BaseNetwork { protected credentials: Credentials; - constructor(credentials: Credentials, apiBase: string, segments: Array) { + constructor(credentials: Credentials, apiBase: string, segments: string[]) { super(apiBase); this.credentials = credentials; this.apiBase = BaseNetwork.urlExtend(this.apiBase, ['api', 'v1'].concat(segments)); } // FIXME: Get the correct type for extra - newCall(segments: Array = [], extra: any = {}, apiBase: any = this.apiBase): Promise<{} | Array> { + public newCall(segments: string[] = [], extra: any = {}, apiBase: any = this.apiBase): Promise<{} | any[]> { extra = Object.assign({}, extra); extra.headers = Object.assign( { 'Content-Type': 'application/json;charset=UTF-8', - 'Authorization': 'Token ' + this.credentials.authToken + 'Authorization': 'Token ' + this.credentials.authToken, }, extra.headers); @@ -408,10 +407,10 @@ export class JournalManager extends BaseManager { super(credentials, apiBase, ['journals', '']); } - fetch(journalUid: string): Promise { + public fetch(journalUid: string): Promise { return new Promise((resolve, reject) => { this.newCall([journalUid, '']).then((json: JournalJson) => { - let journal = new Journal(json.version); + const journal = new Journal(json.version); journal.deserialize(json); resolve(journal); }).catch((error: Error) => { @@ -420,11 +419,11 @@ export class JournalManager extends BaseManager { }); } - list(): Promise { + public list(): Promise { return new Promise((resolve, reject) => { this.newCall().then((json: Array<{}>) => { resolve(json.map((val: JournalJson) => { - let journal = new Journal(val.version); + const journal = new Journal(val.version); journal.deserialize(val); return journal; })); @@ -434,7 +433,7 @@ export class JournalManager extends BaseManager { }); } - create(journal: Journal): Promise<{}> { + public create(journal: Journal): Promise<{}> { const extra = { method: 'post', body: JSON.stringify(journal.serialize()), @@ -443,7 +442,7 @@ export class JournalManager extends BaseManager { return this.newCall([], extra); } - update(journal: Journal): Promise<{}> { + public update(journal: Journal): Promise<{}> { const extra = { method: 'put', body: JSON.stringify(journal.serialize()), @@ -452,7 +451,7 @@ export class JournalManager extends BaseManager { return this.newCall([journal.uid, ''], extra); } - delete(journal: Journal): Promise<{}> { + public delete(journal: Journal): Promise<{}> { const extra = { method: 'delete', }; @@ -466,7 +465,7 @@ export class EntryManager extends BaseManager { super(credentials, apiBase, ['journals', journalId, 'entries', '']); } - list(lastUid: string | null, limit: number = 0): Promise { + public list(lastUid: string | null, limit: number = 0): Promise { let apiBase = this.apiBase.clone(); apiBase = apiBase.search({ last: (lastUid !== null) ? lastUid : undefined, @@ -476,7 +475,7 @@ export class EntryManager extends BaseManager { return new Promise((resolve, reject) => { this.newCall(undefined, undefined, apiBase).then((json: Array<{}>) => { resolve(json.map((val: any) => { - let entry = new Entry(); + const entry = new Entry(); entry.deserialize(val); return entry; })); @@ -486,7 +485,7 @@ export class EntryManager extends BaseManager { }); } - create(entries: Entry[], lastUid: string | null): Promise<{}> { + public create(entries: Entry[], lastUid: string | null): Promise<{}> { let apiBase = this.apiBase.clone(); apiBase = apiBase.search({ last: (lastUid !== null) ? lastUid : undefined, @@ -511,7 +510,7 @@ export class JournalMembersManager extends BaseManager { super(credentials, apiBase, ['journals', journalId, 'members', '']); } - list(): Promise { + public list(): Promise { return new Promise((resolve, reject) => { this.newCall().then((json: Array<{}>) => { resolve(json.map((val: JournalMemberJson) => { @@ -529,10 +528,10 @@ export class UserInfoManager extends BaseManager { super(credentials, apiBase, ['user', '']); } - fetch(owner: string): Promise { + public fetch(owner: string): Promise { return new Promise((resolve, reject) => { this.newCall([owner, '']).then((json: UserInfoJson) => { - let userInfo = new UserInfo(owner, json.version); + const userInfo = new UserInfo(owner, json.version); userInfo.deserialize(json); resolve(userInfo); }).catch((error: Error) => { @@ -541,7 +540,7 @@ export class UserInfoManager extends BaseManager { }); } - create(userInfo: UserInfo): Promise<{}> { + public create(userInfo: UserInfo): Promise<{}> { const extra = { method: 'post', body: JSON.stringify(userInfo.serialize()), @@ -550,7 +549,7 @@ export class UserInfoManager extends BaseManager { return this.newCall([], extra); } - update(userInfo: UserInfo): Promise<{}> { + public update(userInfo: UserInfo): Promise<{}> { const extra = { method: 'put', body: JSON.stringify(userInfo.serialize()), @@ -559,7 +558,7 @@ export class UserInfoManager extends BaseManager { return this.newCall([userInfo.owner, ''], extra); } - delete(userInfo: UserInfo): Promise<{}> { + public delete(userInfo: UserInfo): Promise<{}> { const extra = { method: 'delete', }; diff --git a/src/api/Helpers.ts b/src/api/Helpers.ts index ed4de1f..e966013 100644 --- a/src/api/Helpers.ts +++ b/src/api/Helpers.ts @@ -2,7 +2,7 @@ export type byte = number; export type base64 = string; export function stringToByteArray(str: string): byte[] { - let ret = []; + const ret = []; for (let i = 0 ; i < str.length ; i++) { ret.push(str.charCodeAt(i)); } diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx index afb5fde..64760f3 100644 --- a/src/components/Contact.tsx +++ b/src/components/Contact.tsx @@ -13,11 +13,11 @@ import PimItemHeader from './PimItemHeader'; import { ContactType } from '../pim-types'; class Contact extends React.PureComponent { - props: { + public props: { item?: ContactType, }; - render() { + public render() { if (this.props.item === undefined) { throw Error('Contact should be defined!'); } @@ -29,7 +29,7 @@ class Contact extends React.PureComponent { const lastModified = (revProp) ? 'Modified: ' + moment(revProp.getFirstValue().toJSDate()).format('LLLL') : undefined; - let lists = []; + const lists = []; function getAllType( propName: string, @@ -57,9 +57,9 @@ class Contact extends React.PureComponent { 'tel', { leftIcon: , - rightIcon: + rightIcon: , }, - (x) => ('tel:' + x), + (x) => ('tel:' + x) )); lists.push(getAllType( @@ -67,44 +67,44 @@ class Contact extends React.PureComponent { { leftIcon: , }, - (x) => ('mailto:' + x), + (x) => ('mailto:' + x) )); lists.push(getAllType( 'impp', { - leftIcon: + leftIcon: , }, (x) => x, (x) => (x.substring(x.indexOf(':') + 1)), - (x) => (x.substring(0, x.indexOf(':'))), + (x) => (x.substring(0, x.indexOf(':'))) )); lists.push(getAllType( 'adr', { - leftIcon: - }, + leftIcon: , + } )); lists.push(getAllType( 'bday', { - leftIcon: + leftIcon: , }, undefined, ((x: any) => moment(x.toJSDate()).format('dddd, LL')), - () => 'Birthday', + () => 'Birthday' )); lists.push(getAllType( 'anniversary', { - leftIcon: + leftIcon: , }, undefined, ((x: any) => moment(x.toJSDate()).format('dddd, LL')), - () => 'Anniversary', + () => 'Anniversary' )); const skips = ['tel', 'email', 'impp', 'adr', 'bday', 'anniversary', 'rev', @@ -126,7 +126,7 @@ class Contact extends React.PureComponent { return values; }); - function listIfNotEmpty(items: Array>) { + function listIfNotEmpty(items: JSX.Element[][]) { if (items.length > 0) { return ( diff --git a/src/components/ContactEdit.tsx b/src/components/ContactEdit.tsx index 1a1871f..da5db66 100644 --- a/src/components/ContactEdit.tsx +++ b/src/components/ContactEdit.tsx @@ -45,7 +45,7 @@ const imppTypes = [ ]; const TypeSelector = (props: any) => { - const types = props.types as {type: string}[]; + const types = props.types as Array<{type: string}>; return (