More tslint fixes.

master
Tom Hacohen 6 years ago
parent 9913adc756
commit 7da0a6009b

@ -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);

@ -43,7 +43,7 @@ const JournalCalendar = journalView(PersistCalendar, Event);
const JournalTaskList = journalView(TaskList, Event);
class Journal extends React.Component<PropsTypeInner> {
state: {
public state: {
tab: number,
};
@ -55,7 +55,7 @@ class Journal extends React.Component<PropsTypeInner> {
};
}
render() {
public render() {
const { theme, isOwner, syncJournal } = this.props;
let currentTab = this.state.tab;
let journalOnly = false;

@ -32,7 +32,7 @@ interface PropsTypeInner extends PropsType {
}
class JournalEdit extends React.PureComponent<PropsTypeInner> {
state = {
public state = {
info: {
uid: '',
type: '',
@ -61,7 +61,7 @@ class JournalEdit extends React.PureComponent<PropsTypeInner> {
}
}
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<PropsTypeInner> {
private onDeleteRequest() {
this.setState({
showDeleteDialog: true
showDeleteDialog: true,
});
}

@ -21,7 +21,7 @@ interface PropsTypeInner extends PropsType {
}
class JournalMembers extends React.PureComponent<PropsTypeInner> {
state = {
public state = {
members: null as EteSync.JournalMemberJson[] | null,
};
@ -29,7 +29,7 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
super(props);
}
render() {
public render() {
const { info } = this.props;
const { members } = this.state;
@ -57,7 +57,7 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
);
}
componentDidMount() {
public componentDidMount() {
this.fetchMembers();
}

@ -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(
<ListItem key={journal.uid} onClick={() => 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 }));
}
}

@ -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 (
<Switch>
<Route
@ -114,7 +114,7 @@ class Journals extends React.PureComponent {
);
}
onItemSave(info: EteSync.CollectionInfo, originalInfo?: EteSync.CollectionInfo) {
public onItemSave(info: EteSync.CollectionInfo, originalInfo?: EteSync.CollectionInfo) {
const journal = new EteSync.Journal();
const cryptoManager = new EteSync.CryptoManager(this.props.etesync.encryptionKey, info.uid);
journal.setInfo(cryptoManager, info);
@ -130,7 +130,7 @@ class Journals extends React.PureComponent {
}
}
onItemDelete(info: EteSync.CollectionInfo) {
public onItemDelete(info: EteSync.CollectionInfo) {
const journal = new EteSync.Journal();
const cryptoManager = new EteSync.CryptoManager(this.props.etesync.encryptionKey, info.uid);
journal.setInfo(cryptoManager, info);
@ -140,7 +140,7 @@ class Journals extends React.PureComponent {
);
}
onCancel() {
public onCancel() {
this.props.history.goBack();
}
}

@ -13,7 +13,7 @@ function objValues(obj: any) {
export function journalView(JournalList: any, JournalItem: any) {
return withRouter(class extends React.PureComponent {
props: {
public props: {
journal: EteSync.Journal,
entries: {[key: string]: any},
history?: History,
@ -24,15 +24,15 @@ export function journalView(JournalList: any, JournalItem: any) {
this.itemClicked = this.itemClicked.bind(this);
}
itemClicked(contact: any) {
public itemClicked(contact: any) {
const uid = contact.uid;
this.props.history!.push(
routeResolver.getRoute('journals._id.items._id', { journalUid: this.props.journal.uid, itemUid: uid }));
}
render() {
let items = this.props.entries;
public render() {
const items = this.props.entries;
return (
<Switch>

@ -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<any>(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 (

@ -28,16 +28,16 @@ const tasksTitle = 'Tasks';
const PersistCalendar = historyPersistor('Calendar')(Calendar);
interface PropsType {
contacts: Array<ContactType>;
events: Array<EventType>;
tasks: Array<TaskType>;
contacts: ContactType[];
events: EventType[];
tasks: TaskType[];
location?: Location;
history?: History;
theme: Theme;
}
class PimMain extends React.PureComponent<PropsType> {
state: {
public state: {
tab: number;
};
@ -51,35 +51,35 @@ class PimMain extends React.PureComponent<PropsType> {
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<PropsType> {
}
}
render() {
public render() {
const { theme } = this.props;
const { tab } = this.state;
const style = {

@ -47,9 +47,9 @@ function objValues(obj: any) {
const itemsSelector = createSelector(
(props: {syncInfo: SyncInfo}) => props.syncInfo,
(syncInfo) => {
let collectionsAddressBook: Array<EteSync.CollectionInfo> = [];
let collectionsCalendar: Array<EteSync.CollectionInfo> = [];
let collectionsTaskList: Array<EteSync.CollectionInfo> = [];
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<EteSync.CollectionInfo>,
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<CollectionRoutesPropsType> {
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 (

@ -28,15 +28,7 @@ class Settings extends React.PureComponent<PropsTypeInner> {
this.handleChange = this.handleChange.bind(this);
}
private handleChange(event: React.ChangeEvent<any>) {
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<PropsTypeInner> {
);
}
onCancel() {
public onCancel() {
this.props.history.goBack();
}
private handleChange(event: React.ChangeEvent<any>) {
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) => {

@ -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<PropsTypeInner> {
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

@ -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<string, SyncInfoJournal>()
);
},
}
);
const PimRouter = withRouter(Pim);
@ -103,7 +103,7 @@ class SyncGate extends React.PureComponent<PropsTypeInner> {
super(props);
}
componentDidMount() {
public componentDidMount() {
const me = this.props.etesync.credentials.email;
const syncAll = () => {
store.dispatch<any>(fetchAll(this.props.etesync, this.props.entries)).then((haveJournals: boolean) => {
@ -153,7 +153,7 @@ class SyncGate extends React.PureComponent<PropsTypeInner> {
}
}
render() {
public render() {
const entryArrays = this.props.entries;
const journals = this.props.journals.value;
@ -162,7 +162,7 @@ class SyncGate extends React.PureComponent<PropsTypeInner> {
} else if (this.props.journals.error) {
return <PrettyError error={this.props.journals.error} />;
} 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});

@ -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'));
}
}

@ -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();

@ -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<T extends BaseItemJson> {
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<JournalJson> {
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<EntryJson> {
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<EntryJson> {
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<UserInfoJson> {
_owner: string;
public _owner: string;
constructor(owner: string, version: number = Constants.CURRENT_VERSION) {
super();
@ -253,20 +252,20 @@ export class UserInfo extends BaseItem<UserInfoJson> {
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<UserInfoJson> {
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<UserInfoJson> {
// FIXME: baseUrl and apiBase should be the right type all around.
class BaseNetwork {
apiBase: any; // FIXME
static urlExtend(_baseUrl: URL, segments: Array<string>): 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<string> = [], extra: any = {}, _apiBase: URL = this.apiBase): Promise<{} | Array<any>> {
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<string> {
public getAuthToken(username: string, password: string): Promise<string> {
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<string>) {
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<string> = [], extra: any = {}, apiBase: any = this.apiBase): Promise<{} | Array<any>> {
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<Journal> {
public fetch(journalUid: string): Promise<Journal> {
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<Journal[]> {
public list(): Promise<Journal[]> {
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<Entry[]> {
public list(lastUid: string | null, limit: number = 0): Promise<Entry[]> {
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<JournalMemberJson[]> {
public list(): Promise<JournalMemberJson[]> {
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<UserInfo> {
public fetch(owner: string): Promise<UserInfo> {
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',
};

@ -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));
}

@ -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: <CommunicationCall />,
rightIcon: <CommunicationChatBubble />
rightIcon: <CommunicationChatBubble />,
},
(x) => ('tel:' + x),
(x) => ('tel:' + x)
));
lists.push(getAllType(
@ -67,44 +67,44 @@ class Contact extends React.PureComponent {
{
leftIcon: <CommunicationEmail />,
},
(x) => ('mailto:' + x),
(x) => ('mailto:' + x)
));
lists.push(getAllType(
'impp',
{
leftIcon: <CommunicationChatBubble />
leftIcon: <CommunicationChatBubble />,
},
(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: <IconHome />
},
leftIcon: <IconHome />,
}
));
lists.push(getAllType(
'bday',
{
leftIcon: <IconDate />
leftIcon: <IconDate />,
},
undefined,
((x: any) => moment(x.toJSDate()).format('dddd, LL')),
() => 'Birthday',
() => 'Birthday'
));
lists.push(getAllType(
'anniversary',
{
leftIcon: <IconDate />
leftIcon: <IconDate />,
},
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<Array<JSX.Element>>) {
function listIfNotEmpty(items: JSX.Element[][]) {
if (items.length > 0) {
return (
<React.Fragment>

@ -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 (
<Select
@ -61,8 +61,8 @@ const TypeSelector = (props: any) => {
};
class ValueType {
type: string;
value: string;
public type: string;
public value: string;
constructor(type?: string, value?: string) {
this.type = type ? type : 'home';
@ -74,7 +74,7 @@ interface ValueTypeComponentProps {
type?: string;
style?: object;
types: {type: string}[];
types: Array<{type: string}>;
name: string;
placeholder: string;
value: ValueType;
@ -112,16 +112,16 @@ const ValueTypeComponent = (props: ValueTypeComponentProps) => {
};
interface PropsType {
collections: Array<EteSync.CollectionInfo>;
collections: EteSync.CollectionInfo[];
initialCollection?: string;
item?: ContactType;
onSave: (contact: ContactType, journalUid: string, originalContact?: ContactType) => void;
onDelete: (contact: ContactType, journalUid: string) => void;
onCancel: () => void;
};
}
class ContactEdit extends React.PureComponent<PropsType> {
state: {
public state: {
uid: string,
fn: string;
phone: ValueType[];
@ -201,7 +201,7 @@ class ContactEdit extends React.PureComponent<PropsType> {
this.onDeleteRequest = this.onDeleteRequest.bind(this);
}
componentWillReceiveProps(nextProps: any) {
public componentWillReceiveProps(nextProps: any) {
if ((this.props.collections !== nextProps.collections) ||
(this.props.initialCollection !== nextProps.initialCollection)) {
if (nextProps.initialCollection) {
@ -212,10 +212,10 @@ class ContactEdit extends React.PureComponent<PropsType> {
}
}
addValueType(name: string, _type?: string) {
public addValueType(name: string, _type?: string) {
const type = _type ? _type : 'home';
this.setState((prevState, props) => {
let newArray = prevState[name].slice(0);
const newArray = prevState[name].slice(0);
newArray.push(new ValueType(type));
return {
...prevState,
@ -224,9 +224,9 @@ class ContactEdit extends React.PureComponent<PropsType> {
});
}
removeValueType(name: string, idx: number) {
public removeValueType(name: string, idx: number) {
this.setState((prevState, props) => {
let newArray = prevState[name].slice(0);
const newArray = prevState[name].slice(0);
newArray.splice(idx, 1);
return {
...prevState,
@ -235,9 +235,9 @@ class ContactEdit extends React.PureComponent<PropsType> {
});
}
handleValueTypeChange(name: string, idx: number, value: ValueType) {
public handleValueTypeChange(name: string, idx: number, value: ValueType) {
this.setState((prevState, props) => {
let newArray = prevState[name].slice(0);
const newArray = prevState[name].slice(0);
newArray[idx] = value;
return {
...prevState,
@ -246,29 +246,29 @@ class ContactEdit extends React.PureComponent<PropsType> {
});
}
handleChange(name: string, value: string) {
public handleChange(name: string, value: string) {
this.setState({
[name]: value
[name]: value,
});
}
handleInputChange(contact: any) {
public handleInputChange(contact: any) {
const name = contact.target.name;
const value = contact.target.value;
this.handleChange(name, value);
}
onSubmit(e: React.FormEvent<any>) {
public onSubmit(e: React.FormEvent<any>) {
e.preventDefault();
let contact = (this.props.item) ?
const contact = (this.props.item) ?
this.props.item.clone()
:
new ContactType(new ICAL.Component(['vcard', [], []]))
;
let comp = contact.comp;
const comp = contact.comp;
comp.updatePropertyWithValue('prodid', '-//iCal.js EteSync Web');
comp.updatePropertyWithValue('version', '4.0');
comp.updatePropertyWithValue('uid', this.state.uid);
@ -282,7 +282,7 @@ class ContactEdit extends React.PureComponent<PropsType> {
return;
}
let prop = new ICAL.Property(name, comp);
const prop = new ICAL.Property(name, comp);
prop.setParameter('type', x.type);
prop.setValue(x.value);
comp.addProperty(prop);
@ -310,13 +310,13 @@ class ContactEdit extends React.PureComponent<PropsType> {
this.props.onSave(contact, this.state.journalUid, this.props.item);
}
onDeleteRequest() {
public onDeleteRequest() {
this.setState({
showDeleteDialog: true
showDeleteDialog: true,
});
}
render() {
public render() {
const styles = {
form: {
},

@ -7,12 +7,12 @@ interface FormErrors {
}
class EncryptionLoginForm extends React.PureComponent {
state: {
public state: {
errors: FormErrors,
encryptionPassword: string;
};
props: {
public props: {
onSubmit: (encryptionPassword: string) => void;
loading?: boolean;
error?: Error;
@ -28,27 +28,27 @@ class EncryptionLoginForm extends React.PureComponent {
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event: React.ChangeEvent<any>) {
public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
[name]: value,
});
}
generateEncryption(e: any) {
public generateEncryption(e: any) {
e.preventDefault();
const encryptionPassword = this.state.encryptionPassword;
let errors: FormErrors = {};
const errors: FormErrors = {};
const fieldRequired = 'This field is required!';
if (!encryptionPassword) {
errors.errorEncryptionPassword = fieldRequired;
}
if (Object.keys(errors).length) {
this.setState({errors: errors});
this.setState({errors});
return;
} else {
this.setState({errors: {}});
@ -57,7 +57,7 @@ class EncryptionLoginForm extends React.PureComponent {
this.props.onSubmit(encryptionPassword);
}
render() {
public render() {
const styles = {
form: {
},

@ -6,7 +6,7 @@ import { IntegrityError } from '../api/EteSync';
import PrettyError from '../widgets/PrettyError';
class ErrorBoundary extends React.Component {
state: {
public state: {
error?: Error;
};
@ -15,7 +15,7 @@ class ErrorBoundary extends React.Component {
this.state = { };
}
componentDidCatch(error: Error, info: any) {
public componentDidCatch(error: Error, info: any) {
if (error instanceof IntegrityError) {
persistor.purge();
}
@ -23,7 +23,7 @@ class ErrorBoundary extends React.Component {
this.setState({ error });
}
render() {
public render() {
const { error } = this.state;
if (error && error instanceof IntegrityError) {
return (

@ -7,11 +7,11 @@ import { formatDateRange } from '../helpers';
import { EventType } from '../pim-types';
class Event extends React.PureComponent {
props: {
public props: {
item?: EventType,
};
render() {
public render() {
if (this.props.item === undefined) {
throw Error('Event should be defined!');
}
@ -27,7 +27,7 @@ class Event extends React.PureComponent {
return (
<React.Fragment>
<PimItemHeader text={this.props.item.summary} backgroundColor={this.props.item.color}>
<div>{formatDateRange(this.props.item.startDate, this.props.item.endDate)} { timezone && <small>({timezone})</small>}</div>
<div>{formatDateRange(this.props.item.startDate, this.props.item.endDate)} {timezone && <small>({timezone})</small>}</div>
<br/>
<div><u>{this.props.item.location}</u></div>
</PimItemHeader>

@ -31,17 +31,17 @@ import * as EteSync from '../api/EteSync';
import { EventType } from '../pim-types';
interface PropsType {
collections: Array<EteSync.CollectionInfo>;
collections: EteSync.CollectionInfo[];
initialCollection?: string;
item?: EventType;
onSave: (event: EventType, journalUid: string, originalEvent?: EventType) => void;
onDelete: (event: EventType, journalUid: string) => void;
onCancel: () => void;
location: Location;
};
}
class EventEdit extends React.PureComponent<PropsType> {
state: {
public state: {
uid: string,
title: string;
allDay: boolean;
@ -84,7 +84,7 @@ class EventEdit extends React.PureComponent<PropsType> {
const event = this.props.item;
const allDay = event.startDate.isDate;
let endDate = event.endDate.clone();
const endDate = event.endDate.clone();
if (allDay) {
endDate.adjust(-1, 0, 0, 0);
@ -114,7 +114,7 @@ class EventEdit extends React.PureComponent<PropsType> {
this.onDeleteRequest = this.onDeleteRequest.bind(this);
}
componentWillReceiveProps(nextProps: any) {
public componentWillReceiveProps(nextProps: any) {
if ((this.props.collections !== nextProps.collections) ||
(this.props.initialCollection !== nextProps.initialCollection)) {
if (nextProps.initialCollection) {
@ -125,24 +125,24 @@ class EventEdit extends React.PureComponent<PropsType> {
}
}
handleChange(name: string, value: string) {
public handleChange(name: string, value: string) {
this.setState({
[name]: value
[name]: value,
});
}
handleInputChange(event: React.ChangeEvent<any>) {
public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
const value = event.target.value;
this.handleChange(name, value);
}
toggleAllDay() {
public toggleAllDay() {
this.setState({allDay: !this.state.allDay});
}
onSubmit(e: React.FormEvent<any>) {
public onSubmit(e: React.FormEvent<any>) {
e.preventDefault();
if ((!this.state.start) || (!this.state.end)) {
@ -155,7 +155,7 @@ class EventEdit extends React.PureComponent<PropsType> {
if (!allDay) {
return ret;
} else {
let data = ret.toJSON();
const data = ret.toJSON();
data.isDate = allDay;
return ICAL.Time.fromData(data);
}
@ -173,7 +173,7 @@ class EventEdit extends React.PureComponent<PropsType> {
return;
}
let event = (this.props.item) ?
const event = (this.props.item) ?
this.props.item.clone()
:
new EventType()
@ -190,13 +190,13 @@ class EventEdit extends React.PureComponent<PropsType> {
this.props.onSave(event, this.state.journalUid, this.props.item);
}
onDeleteRequest() {
public onDeleteRequest() {
this.setState({
showDeleteDialog: true
showDeleteDialog: true,
});
}
render() {
public render() {
const styles = {
form: {
},

@ -18,15 +18,15 @@ import { TaskType, EventType, ContactType } from '../pim-types';
import * as EteSync from '../api/EteSync';
class JournalEntries extends React.PureComponent {
static defaultProps = {
public static defaultProps = {
prevUid: null,
};
state: {
public state: {
dialog?: string;
};
props: {
public props: {
journal: EteSync.Journal,
entries: Immutable.List<EteSync.SyncEntry>,
uid?: string,
@ -37,7 +37,7 @@ class JournalEntries extends React.PureComponent {
this.state = {};
}
render() {
public render() {
if (this.props.journal === undefined) {
return (<div>Loading</div>);
}
@ -87,7 +87,7 @@ class JournalEntries extends React.PureComponent {
secondaryText={uid}
onClick={() => {
this.setState({
dialog: syncEntry.content
dialog: syncEntry.content,
});
}}
/>

@ -17,7 +17,7 @@ interface FormErrors {
}
class LoginForm extends React.PureComponent {
state: {
public state: {
showAdvanced: boolean;
errors: FormErrors;
@ -27,7 +27,7 @@ class LoginForm extends React.PureComponent {
encryptionPassword: string;
};
props: {
public props: {
onSubmit: (username: string, password: string, encryptionPassword: string, serviceApiUrl?: string) => void;
loading?: boolean;
error?: Error;
@ -48,15 +48,15 @@ class LoginForm extends React.PureComponent {
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event: React.ChangeEvent<any>) {
public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
[name]: value,
});
}
generateEncryption(e: any) {
public generateEncryption(e: any) {
e.preventDefault();
const server = this.state.showAdvanced ? this.state.server : undefined;
@ -64,7 +64,7 @@ class LoginForm extends React.PureComponent {
const password = this.state.password;
const encryptionPassword = this.state.encryptionPassword;
let errors: FormErrors = {};
const errors: FormErrors = {};
const fieldRequired = 'This field is required!';
if (!username) {
errors.errorEmail = fieldRequired;
@ -83,7 +83,7 @@ class LoginForm extends React.PureComponent {
}
if (Object.keys(errors).length) {
this.setState({errors: errors});
this.setState({errors});
return;
} else {
this.setState({errors: {}});
@ -92,11 +92,11 @@ class LoginForm extends React.PureComponent {
this.props.onSubmit(username, password, encryptionPassword, server);
}
toggleAdvancedSettings() {
public toggleAdvancedSettings() {
this.setState({showAdvanced: !this.state.showAdvanced});
}
render() {
public render() {
const styles = {
form: {
},

@ -11,12 +11,12 @@ import { ContactType } from '../pim-types';
import AddressBook from '../components/AddressBook';
class SearchableAddressBook extends React.PureComponent {
props: {
entries: Array<ContactType>,
public props: {
entries: ContactType[],
onItemClick: (contact: ContactType) => void,
};
state: {
public state: {
searchQuery: string;
};
@ -26,15 +26,15 @@ class SearchableAddressBook extends React.PureComponent {
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event: React.ChangeEvent<any>) {
public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
[name]: value,
});
}
render() {
public render() {
const {
entries,
...rest
@ -52,7 +52,7 @@ class SearchableAddressBook extends React.PureComponent {
onChange={this.handleInputChange}
/>
{this.state.searchQuery &&
<IconButton onClick={() => this.setState({'searchQuery': ''})}>
<IconButton onClick={() => this.setState({searchQuery: ''})}>
<IconClear />
</IconButton>
}

@ -7,11 +7,11 @@ import { formatDate } from '../helpers';
import { TaskType } from '../pim-types';
class Task extends React.PureComponent {
props: {
public props: {
item?: TaskType,
};
render() {
public render() {
if (this.props.item === undefined) {
throw Error('Task should be defined!');
}
@ -30,10 +30,10 @@ class Task extends React.PureComponent {
<React.Fragment>
<PimItemHeader text={this.props.item.summary} backgroundColor={this.props.item.color}>
{ item.startDate &&
<div>Start: {formatDate(item.startDate)} { timezone && <small>({timezone})</small>}</div>
<div>Start: {formatDate(item.startDate)} {timezone && <small>({timezone})</small>}</div>
}
{ item.dueDate &&
<div>Due: {formatDate(item.dueDate)} { timezone && <small>({timezone})</small>}</div>
<div>Due: {formatDate(item.dueDate)} {timezone && <small>({timezone})</small>}</div>
}
<br/>
<div><u>{this.props.item.location}</u></div>

@ -31,17 +31,17 @@ import * as EteSync from '../api/EteSync';
import { TaskType, TaskStatusType } from '../pim-types';
interface PropsType {
collections: Array<EteSync.CollectionInfo>;
collections: EteSync.CollectionInfo[];
initialCollection?: string;
item?: TaskType;
onSave: (item: TaskType, journalUid: string, originalItem?: TaskType) => void;
onDelete: (item: TaskType, journalUid: string) => void;
onCancel: () => void;
location: Location;
};
}
class TaskEdit extends React.PureComponent<PropsType> {
state: {
public state: {
uid: string,
title: string;
status: TaskStatusType;
@ -102,7 +102,7 @@ class TaskEdit extends React.PureComponent<PropsType> {
this.onDeleteRequest = this.onDeleteRequest.bind(this);
}
componentWillReceiveProps(nextProps: any) {
public componentWillReceiveProps(nextProps: any) {
if ((this.props.collections !== nextProps.collections) ||
(this.props.initialCollection !== nextProps.initialCollection)) {
if (nextProps.initialCollection) {
@ -113,24 +113,24 @@ class TaskEdit extends React.PureComponent<PropsType> {
}
}
handleChange(name: string, value: string) {
public handleChange(name: string, value: string) {
this.setState({
[name]: value
[name]: value,
});
}
handleInputChange(event: React.ChangeEvent<any>) {
public handleInputChange(event: React.ChangeEvent<any>) {
const name = event.target.name;
const value = event.target.value;
this.handleChange(name, value);
}
toggleAllDay() {
public toggleAllDay() {
this.setState({allDay: !this.state.allDay});
}
onSubmit(e: React.FormEvent<any>) {
public onSubmit(e: React.FormEvent<any>) {
e.preventDefault();
function fromDate(date: Date | undefined, allDay: boolean) {
@ -141,7 +141,7 @@ class TaskEdit extends React.PureComponent<PropsType> {
if (!allDay) {
return ret;
} else {
let data = ret.toJSON();
const data = ret.toJSON();
data.isDate = allDay;
return ICAL.Time.fromData(data);
}
@ -157,7 +157,7 @@ class TaskEdit extends React.PureComponent<PropsType> {
}
}
let event = (this.props.item) ?
const event = (this.props.item) ?
this.props.item.clone()
:
new TaskType(null)
@ -178,13 +178,13 @@ class TaskEdit extends React.PureComponent<PropsType> {
this.props.onSave(event, this.state.journalUid, this.props.item);
}
onDeleteRequest() {
public onDeleteRequest() {
this.setState({
showDeleteDialog: true
showDeleteDialog: true,
});
}
render() {
public render() {
const styles = {
form: {
},

@ -23,7 +23,7 @@ const TaskListItem = pure((_props: any) => {
});
const sortSelector = createSelector(
(entries: Array<TaskType>) => entries,
(entries: TaskType[]) => entries,
(entries) => {
return entries.sort((_a, _b) => {
const a = _a.title;
@ -37,20 +37,20 @@ const sortSelector = createSelector(
return 0;
}
});
},
}
);
class TaskList extends React.PureComponent {
props: {
entries: Array<TaskType>,
public props: {
entries: TaskType[],
onItemClick: (contact: TaskType) => void,
};
render() {
public render() {
const entries = this.props.entries.filter((x) => !x.finished);
const sortedEntries = sortSelector(entries);
let itemList = sortedEntries.map((entry, idx, array) => {
const itemList = sortedEntries.map((entry, idx, array) => {
const uid = entry.uid;
return (

@ -2,12 +2,12 @@ import * as React from 'react';
import { withRouter } from 'react-router';
// FIXME: Should probably tie this to the history object, or at least based on the depth of the history
let stateCache = {};
const stateCache = {};
type Constructor<T> = new(...args: any[]) => T;
export function historyPersistor(tag: string) {
return function<T extends Constructor<React.Component>>(Base: T) {
return <T extends Constructor<React.Component>>(Base: T) => {
return withRouter(class extends Base {
constructor(...rest: any[]) {
const props = rest[0];
@ -18,14 +18,14 @@ export function historyPersistor(tag: string) {
}
}
componentWillUnmount() {
public componentWillUnmount() {
if (super.componentWillUnmount) {
super.componentWillUnmount();
}
stateCache[this.getKeyForTag(this.props, tag)] = this.state;
}
getKeyForTag(props: any, tagName: string) {
public getKeyForTag(props: any, tagName: string) {
return props.location.pathname + ':' + tagName;
}
});

@ -50,7 +50,7 @@ export default function register() {
function registerValidSW(swUrl: string) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker) {
@ -73,7 +73,7 @@ function registerValidSW(swUrl: string) {
}
};
})
.catch(error => {
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
@ -81,14 +81,14 @@ function registerValidSW(swUrl: string) {
function checkValidServiceWorker(swUrl: string) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type')!.indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
@ -107,7 +107,7 @@ function checkValidServiceWorker(swUrl: string) {
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}

Loading…
Cancel
Save