Skip to content

Commit

Permalink
Explore end-to-end encryption for data (v2, userbase)
Browse files Browse the repository at this point in the history
This enables end-to-end encryption via Userbase. Everything works and is fast (unlike Etebase), though it still lacks billing control.

All dependencies were updated, as the starting point was #1
  • Loading branch information
BrunoBernardino committed Jan 4, 2022
1 parent 011fe18 commit 3684230
Show file tree
Hide file tree
Showing 18 changed files with 474 additions and 858 deletions.
2 changes: 1 addition & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NODE_PATH=/
AWS_ACCESS_KEY_ID=accesskey
AWS_SECRET_ACCESS_KEY=sshhh
NEXT_PUBLIC_ETEBASE_SERVER_URL=https://api.etebase.com/example
NEXT_PUBLIC_USERBASE_APP_ID=get-from-userbase.com
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This is the web app for the [Budget Zen app](https://budgetzen.net), built with Next.js and deployed to AWS with Serverless.

It's v2, meaning it is [end-to-end encrypted via etebase](https://etebase.com), and requires an email + [token](https://budgetzen.net/get-sync-token) to work.
It's v2, meaning it is [end-to-end encrypted via userbase](https://userbase.com), and requires an email + password to work.

It also means it's not compatible with Budget Zen v1, which you can still get locally from [this commit](https://github.com/BrunoBernardino/budgetzen-web/tree/397d625469b7dfd8d1968c847b32e607ee7c8ee9).

Expand All @@ -20,11 +20,7 @@ make deploy # deploys to v2.budgetzen.net (requires `serverless` to be installe

## TODOs

- [ ] Implement billing in signup

## TODOs for later

- [ ] Implement encrypted session (always ask for a pin)?
- [ ] Implement billing: https://userbase.com/docs/sdk/purchase-subscription/
- [ ] Implement changing/forgetting password: https://userbase.com/docs/sdk/forgot-password/ && https://userbase.com/docs/sdk/update-user/
- [ ] Improve UI/UX in general
- [ ] Improve dark/light mode
- [ ] Implement [Signed Pages](https://github.com/tasn/webext-signed-pages)?
8 changes: 3 additions & 5 deletions components/BudgetModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useState, useCallback } from 'react';
import styled from 'styled-components';
import Rodal from 'rodal';
import Swal from 'sweetalert2';
import * as Etebase from 'etebase';

import Button from 'components/Button';
import { showNotification } from 'lib/utils';
Expand All @@ -18,7 +17,6 @@ interface BudgetModalProps {
month: string;
value: number;
reloadData: () => Promise<void>;
etebase: Etebase.Account;
}

const Container = styled.section`
Expand Down Expand Up @@ -65,7 +63,7 @@ const BudgetModal = (props: BudgetModalProps) => {
const [month, setMonth] = useState(`${props.month}-01`);
const [value, setValue] = useState(props.value.toString());

const { id, isOpen, reloadData, etebase } = props;
const { id, isOpen, reloadData } = props;

const onClose = useCallback(() => {
const { onClose: closeModal } = props;
Expand All @@ -90,7 +88,7 @@ const BudgetModal = (props: BudgetModalProps) => {
month: month ? month.substring(0, 7) : '',
};

const success = await saveBudget(etebase, parsedBudget);
const success = await saveBudget(parsedBudget);

setIsSubmitting(false);

Expand Down Expand Up @@ -124,7 +122,7 @@ const BudgetModal = (props: BudgetModalProps) => {

setIsSubmitting(true);

const success = await deleteBudget(etebase, id);
const success = await deleteBudget(id);

setIsSubmitting(false);

Expand Down
8 changes: 3 additions & 5 deletions components/ExpenseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useState, useCallback } from 'react';
import styled from 'styled-components';
import Rodal from 'rodal';
import Swal from 'sweetalert2';
import * as Etebase from 'etebase';

import Button from 'components/Button';
import { showNotification } from 'lib/utils';
Expand All @@ -20,7 +19,6 @@ interface ExpenseModalProps {
date: string;
budgets: T.Budget[];
reloadData: () => Promise<void>;
etebase: Etebase.Account;
}

const Container = styled.section`
Expand Down Expand Up @@ -89,7 +87,7 @@ const ExpenseModal = (props: ExpenseModalProps) => {
const [budget, setBudget] = useState(props.budget);
const [date, setDate] = useState(props.date);

const { id, isOpen, budgets, reloadData, etebase } = props;
const { id, isOpen, budgets, reloadData } = props;

const onClose = useCallback(() => {
const { onClose: closeModal } = props;
Expand All @@ -116,7 +114,7 @@ const ExpenseModal = (props: ExpenseModalProps) => {
date,
};

const success = await saveExpense(etebase, parsedExpense);
const success = await saveExpense(parsedExpense);

setIsSubmitting(false);

Expand Down Expand Up @@ -150,7 +148,7 @@ const ExpenseModal = (props: ExpenseModalProps) => {

setIsSubmitting(true);

const success = await deleteExpense(etebase, id);
const success = await deleteExpense(id);

setIsSubmitting(false);

Expand Down
9 changes: 2 additions & 7 deletions components/ImportExportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useState } from 'react';
import styled from 'styled-components';
import Rodal from 'rodal';
import Swal from 'sweetalert2';
import * as Etebase from 'etebase';

import Button from 'components/Button';
import { showNotification } from 'lib/utils';
Expand All @@ -16,8 +15,6 @@ type ImportedFileData = {
};

interface ImportExportModalProps {
etebase: Etebase.Account;
session: string;
isOpen: boolean;
onClose: () => void;
setIsLoading: (isLoading: boolean) => void;
Expand Down Expand Up @@ -50,7 +47,7 @@ const Note = styled.span`
const ImportExportModal = (props: ImportExportModalProps) => {
const [isSubmitting, setIsSubmitting] = useState(false);

const { isOpen, onClose, etebase, session, setIsLoading } = props;
const { isOpen, onClose, setIsLoading } = props;

const onRequestImport = async () => {
if (isSubmitting) {
Expand Down Expand Up @@ -117,8 +114,6 @@ const ImportExportModal = (props: ImportExportModalProps) => {
setIsLoading(true);

const success = await importData(
etebase,
session,
mergeOrReplaceDialogResult.isDenied,
budgets,
expenses,
Expand Down Expand Up @@ -149,7 +144,7 @@ const ImportExportModal = (props: ImportExportModalProps) => {
.substring(0, 19)
.replace(/:/g, '-')}.json`;

const exportData = await exportAllData(etebase);
const exportData = await exportAllData();

const exportContents = JSON.stringify(exportData, null, 2);

Expand Down
6 changes: 2 additions & 4 deletions components/Panels/AddExpense.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState, useCallback } from 'react';
import styled from 'styled-components';
import * as Etebase from 'etebase';

import Button from 'components/Button';
import { colors, fontSizes } from 'lib/constants';
Expand All @@ -11,7 +10,6 @@ import * as T from 'lib/types';
interface AddExpenseProps {
budgets: T.Budget[];
reloadData: () => Promise<void>;
etebase: Etebase.Account;
}

const Container = styled.section`
Expand Down Expand Up @@ -89,7 +87,7 @@ const Select = styled.select`
}
`;

const AddExpense = ({ budgets, reloadData, etebase }: AddExpenseProps) => {
const AddExpense = ({ budgets, reloadData }: AddExpenseProps) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [description, setDescription] = useState('');
const [cost, setCost] = useState('');
Expand All @@ -112,7 +110,7 @@ const AddExpense = ({ budgets, reloadData, etebase }: AddExpenseProps) => {
date,
};

const success = await saveExpense(etebase, parsedExpense);
const success = await saveExpense(parsedExpense);

setIsSubmitting(false);

Expand Down
37 changes: 7 additions & 30 deletions components/Panels/All.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useState, useRef, useEffect } from 'react';
import React, { useState, useEffect } from 'react';
import moment from 'moment';
import styled from 'styled-components';
import { useAsync } from 'react-use';
import * as Etebase from 'etebase';

import LogoutLink from 'modules/auth/LogoutLink';
import { Loading } from 'components';
Expand Down Expand Up @@ -46,11 +45,9 @@ const All = () => {
const [isLoading, setIsLoading] = useState(true);
const [monthInView, setMonthInView] = useState(moment().format('YYYY-MM'));
const [currency, setCurrency] = useState<T.Currency>('USD');
const [session, setSession] = useState('');
const [theme, setTheme] = useState<T.Theme>('light');
const [budgets, setBudgets] = useState<T.Budget[]>([]);
const [expenses, setExpenses] = useState<T.Expense[]>([]);
const etebase = useRef<Etebase.Account>(null);

type ReloadData = (options?: {
monthToLoad?: string;
Expand All @@ -62,16 +59,10 @@ const All = () => {
} = {}) => {
setIsLoading(true);

const fetchedBudgets = await fetchBudgets(
etebase.current,
monthToLoad || monthInView,
);
const fetchedBudgets = await fetchBudgets(monthToLoad || monthInView);
setBudgets(fetchedBudgets);

const fetchedExpenses = await fetchExpenses(
etebase.current,
monthToLoad || monthInView,
);
const fetchedExpenses = await fetchExpenses(monthToLoad || monthInView);
setExpenses(fetchedExpenses);

// If this is for the current or next month and there are no budgets, create budgets based on the previous/current month.
Expand All @@ -84,7 +75,7 @@ const All = () => {
(monthToLoad && monthToLoad === nextMonth) ||
(!monthToLoad && monthInView === nextMonth)
) {
await copyBudgets(etebase.current, currentMonth, nextMonth);
await copyBudgets(currentMonth, nextMonth);
await reloadData({ monthToLoad, isComingFromEmptyState: true });
return;
}
Expand All @@ -93,7 +84,7 @@ const All = () => {
(monthToLoad && monthToLoad === currentMonth) ||
(!monthToLoad && monthInView === currentMonth)
) {
await copyBudgets(etebase.current, previousMonth, currentMonth);
await copyBudgets(previousMonth, currentMonth);
await reloadData({ monthToLoad, isComingFromEmptyState: true });
return;
}
Expand All @@ -120,16 +111,10 @@ const All = () => {
const userInfo = getUserInfo();
setCurrency(userInfo.currency);
setTheme(userInfo.theme || 'light');
setSession(userInfo.session);

const initializedDb = await initializeDb(userInfo.session);
etebase.current = initializedDb;
await initializeDb();

await reloadData();

showNotification(
'Data is continuously synchronizing in the background. Navigate between months to see the latest data.',
);
}
}, []);

Expand All @@ -155,28 +140,20 @@ const All = () => {
budgets={budgets}
expenses={expenses}
reloadData={reloadData}
etebase={etebase.current}
/>
<Budgets
monthInView={monthInView}
currency={currency}
budgets={budgets}
expenses={expenses}
reloadData={reloadData}
etebase={etebase.current}
/>
</Wrapper>
</LeftSide>
<AddExpense
budgets={budgets}
reloadData={reloadData}
etebase={etebase.current}
/>
<AddExpense budgets={budgets} reloadData={reloadData} />
<Settings
currentCurrency={currency}
updateCurrency={setCurrency}
session={session}
etebase={etebase.current}
currentTheme={theme}
updateTheme={setTheme}
setIsLoading={setIsLoading}
Expand Down
2 changes: 0 additions & 2 deletions components/Panels/Budgets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ const Budgets = ({
budgets,
expenses,
reloadData,
etebase,
}: BudgetsProps) => {
const [isBudgetModalOpen, setIsBudgetModalOpen] = useState(false);
const [chosenBudget, setChosenBudget] = useState({
Expand Down Expand Up @@ -148,7 +147,6 @@ const Budgets = ({
isOpen={isBudgetModalOpen}
onClose={() => closeBudgetModal()}
reloadData={reloadData}
etebase={etebase}
{...chosenBudget}
/>
</Container>
Expand Down
2 changes: 0 additions & 2 deletions components/Panels/Expenses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ const Expenses = ({
budgets,
currency,
reloadData,
etebase,
}: ExpensesProps) => {
const [filterExpenseDescription, setFilterExpenseDescription] = useState('');
const [filterBudgets, setFilterBudgets] = useState<Set<string>>(new Set());
Expand Down Expand Up @@ -181,7 +180,6 @@ const Expenses = ({
onClose={() => closeExpenseModal()}
budgets={budgets}
reloadData={reloadData}
etebase={etebase}
{...chosenExpense}
/>
<FilterBudgetModal
Expand Down
13 changes: 3 additions & 10 deletions components/Panels/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import Rodal from 'rodal';
import * as Etebase from 'etebase';

import SegmentedControl from 'components/SegmentedControl';
import Button from 'components/Button';
import IconButton from 'components/IconButton';
import ImportExportModal from 'components/ImportExportModal';
import { colors, fontSizes } from 'lib/constants';
import { doLogin, showNotification } from 'lib/utils';
import { updatePreferences, showNotification } from 'lib/utils';
import * as T from 'lib/types';

import appPackage from '../../package.json';
Expand All @@ -18,8 +17,6 @@ interface SettingsProps {
updateCurrency: (currency: T.Currency) => void;
currentTheme: T.Theme;
updateTheme: (theme: T.Theme) => void;
session: string;
etebase: Etebase.Account;
setIsLoading: (isLoading: boolean) => void;
reloadData: () => Promise<void>;
}
Expand Down Expand Up @@ -80,8 +77,6 @@ const Settings = ({
updateCurrency,
currentTheme,
updateTheme,
session,
etebase,
setIsLoading,
reloadData,
}: SettingsProps) => {
Expand All @@ -107,7 +102,7 @@ const Settings = ({

setIsSubmitting(true);

const success = doLogin(session, newCurrency, currentTheme);
const success = updatePreferences(newCurrency, currentTheme);

if (success) {
updateCurrency(newCurrency);
Expand All @@ -127,7 +122,7 @@ const Settings = ({

setIsSubmitting(true);

const success = doLogin(session, currentCurrency, newTheme);
const success = updatePreferences(currentCurrency, newTheme);

if (success) {
updateTheme(newTheme);
Expand Down Expand Up @@ -208,8 +203,6 @@ const Settings = ({
</Button>
</BottomContainer>
<ImportExportModal
etebase={etebase}
session={session}
isOpen={isImportExportModalOpen}
onClose={async () => {
setIsImportExportModalOpen(false);
Expand Down
Loading

0 comments on commit 3684230

Please sign in to comment.