Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 33 additions & 33 deletions src/electron/App/CommunicationMessages.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
export type IMessages = {
downloadLinkWritten: {
ok: string
},
accountAndDataDeleted: {
ok: string
fail: string
},
dataDeleted: {
ok: string
fail: string
},
generic: {
ok: string,
fail: string
}
downloadLinkWritten: {
ok: string
}
accountAndDataDeleted: {
ok: string
fail: string
}
dataDeleted: {
ok: string
fail: string
}
generic: {
ok: string
fail: string
}
}

const en: IMessages = {
downloadLinkWritten: {
ok: `The link was written to the clipboard.\nPaste it in a browser and the database will download.\nRemember to keep it a secret!`
},
accountAndDataDeleted: {
ok: "Account and your data were successfully deleted",
fail: "Failed to delete your account and/or data"
},
dataDeleted: {
ok: "Failed to delete your data",
fail: "Data successfully deleted"
},
generic: {
ok: "Operation successfully completed",
fail: "Operation failed"
}
downloadLinkWritten: {
ok: `The link was written to the clipboard.\nPaste it in a browser and the database will download.\nRemember to keep it a secret!`
},
accountAndDataDeleted: {
ok: 'Account and your data were successfully deleted',
fail: 'Failed to delete your account and/or data'
},
dataDeleted: {
ok: 'Failed to delete your data',
fail: 'Data successfully deleted'
},
generic: {
ok: 'Operation successfully completed',
fail: 'Operation failed'
}
}

export const messages = (lang: "en" | "tbd" = "en"): IMessages => {
return en
}
export const messages = (lang: 'en' | 'tbd' = 'en'): IMessages => {
return en
}
29 changes: 28 additions & 1 deletion src/electron/App/EventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ async function registerUser(rawUser: { name: string; password: string }) {
}

/**
* Events send by the front-end, not Iohook specific
* from frontend, not Iohook specific
*/
const channelsFromRender: IReceiveChannel[] = [
{
Expand Down Expand Up @@ -484,6 +484,33 @@ const channelsFromRender: IReceiveChannel[] = [
handler: async (event: any) => {
actionsExported.askPassword()
}
},
{
name: 'to.backend.openImage',
handler: async (event: any, hash: string, width: number, height: number) => {
const item = await ItemRepo.get(hash)
if (!item || item.contentType !== 3) {
actionsExported.alertFrontend('cannot open a non image')
}
const win = new BrowserWindow({
height,
width,
show: false,
autoHideMenuBar: true
})

const content = `data:text/html;charset=utf-8,<html><head><title>image taken on ${item?.modified.toLocaleString()}</title></head><body> <img style="height: 100%;" src="${
item?.content
}"></body></html>`
win.loadURL(content)
win.setAlwaysOnTop(true, 'floating')
win.setVisibleOnAllWorkspaces(true)
win.once('ready-to-show', () => {
win.show()
})
win.focus()
win
}
}
]

Expand Down
20 changes: 9 additions & 11 deletions src/electron/Data/ItemRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ const update = (item: IClipboardItem): boolean => {
return false
}


const remove = async (hash: string) => {
items.delete(hash)
await RequestService.clips.delete(hash)
Expand Down Expand Up @@ -96,7 +95,7 @@ async function loadItemsBeforeDate(date: DateTime, limit: number, masterKey: str
}
let needsLoading = false
if (!state.user) {
throw new Error("user not found")
throw new Error('user not found')
}
// console.log("received items: " + res.data.clips.length)
for (const clip of res.data.clips) {
Expand Down Expand Up @@ -136,18 +135,18 @@ export const ItemRepo = {
loadItemsBeforeHash: async (hash: string, password: string, limit = 50) => {
const item = items.get(hash)
if (!item) {
throw new Error("tried to read before unexisting hash!")
throw new Error('tried to read before unexisting hash!')
}
return loadItemsBeforeDate(DateTime.fromJSDate(item.modified), limit, password)
},
cleanUp: async (maxAgeInSeconds: number, maxNumberTotal: number): Promise<boolean> => {
let changed = false
changed = changed || await removeOldUnfavored(maxAgeInSeconds)
changed = changed || await limitMapSize(maxNumberTotal)
changed = changed || (await removeOldUnfavored(maxAgeInSeconds))
changed = changed || (await limitMapSize(maxNumberTotal))
return changed
},
syncWithRemote: async (password: string) => {
console.log("syncing")
console.log('syncing')
const res = await RequestService.clips.getSince(oldestPull)
if (!res.ok || !res.data) {
actionsExported.logFrontend(messages().generic.fail + `.\nFetch of items since ${oldestPull.toISO()}.`)
Expand All @@ -156,9 +155,9 @@ export const ItemRepo = {
oldestPull = DateTime.now()
let needsLoading = false
if (!state.user) {
throw new Error("user not found")
throw new Error('user not found')
}
console.log("received items after sync: " + res.data.clips.length)
console.log('received items after sync: ' + res.data.clips.length)
for (const clip of res.data.clips) {
needsLoading = true
try {
Expand All @@ -185,8 +184,7 @@ export const ItemRepo = {
item[1].remoteStatus = RemoteItemStatus.pushedToRemote
} else if (res.status == 409) {
item[1].remoteStatus = RemoteItemStatus.needsUpdateOnRemote
}
else {
} else {
console.log(await res.text())
}
needsLoading = true
Expand All @@ -204,7 +202,7 @@ export const ItemRepo = {
}
console.log('done syncing')
if (needsLoading) {
console.log("needs loading after remote sync")
console.log('needs loading after remote sync')
actionsExported.sendCurrentItems()
}
}
Expand Down
11 changes: 4 additions & 7 deletions src/electron/Data/RequestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ export const ClipsEndpoints = {
CreateUpdate: `${userPreferences.storeUrl.value}/v1/clips`,
Delete: (hash: string) => `${userPreferences.storeUrl.value}/v1/clips/${hash}`,
GetOne: (hash: string) => `${userPreferences.storeUrl.value}/v1/clips/${hash}`,
GetAllSince: (time: DateTime) =>
`${userPreferences.storeUrl.value}/v1/clips/since/${time.toUTC().toISO()}`,
GetAllSince: (time: DateTime) => `${userPreferences.storeUrl.value}/v1/clips/since/${time.toUTC().toISO()}`,
GetNBefore: (time: DateTime, limit: number) =>
`${userPreferences.storeUrl.value}/v1/clips/before/${time.toUTC().toISO()}/limit/${limit}`,
GetInBetween: (start: DateTime, end: DateTime) =>
`${userPreferences.storeUrl.value}/v1/clips/between/${start.toUTC().toISO()}/${end.toUTC().toISO()}`,
DeletAllData: () =>
`${userPreferences.storeUrl.value}/v1/deleteMyData`,
GetDatabaseFile: () =>
`${userPreferences.storeUrl.value}/v1/database`
DeletAllData: () => `${userPreferences.storeUrl.value}/v1/deleteMyData`,
GetDatabaseFile: () => `${userPreferences.storeUrl.value}/v1/database`
}

export const UserEndpoints = {
Register: `${userPreferences.authUrl.value}/v1/register`,
Login: `${userPreferences.authUrl.value}/v1/login`,
RefreshToken: `${userPreferences.authUrl.value}/v1/refresh`,
DeleteProfile: `${userPreferences.authUrl.value}/v1/deleteAccount`,
Confirm2FA: `${userPreferences.authUrl.value}/v1/confirm2fa`,
Confirm2FA: `${userPreferences.authUrl.value}/v1/confirm2fa`
}
82 changes: 49 additions & 33 deletions src/electron/Data/Requests.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DateTime } from "luxon"
import { DateTime } from 'luxon'
import fetch from 'node-fetch'
import { actionsExported } from "../App/EventHandler"
import { IClipboardItemEncrypted } from "../DataModels/DataTypes"
import { BulkRes, CommonRes, LoginRes, RefreshRes, RegisterRes } from "../DataModels/RequestTypes"
import { ClipsEndpoints, UserEndpoints } from "./RequestUtils"
import { actionsExported } from '../App/EventHandler'
import { IClipboardItemEncrypted } from '../DataModels/DataTypes'
import { BulkRes, CommonRes, LoginRes, RefreshRes, RegisterRes } from '../DataModels/RequestTypes'
import { ClipsEndpoints, UserEndpoints } from './RequestUtils'

export const userTokens: Tokens = {
access_expires: DateTime.now()
Expand All @@ -15,12 +15,12 @@ type Tokens = {
access_expires: DateTime<true>
}

function request(url: string, method: string = "GET", body?: object, headers?: Record<string, string>) {
function request(url: string, method: string = 'GET', body?: object, headers?: Record<string, string>) {
if (!headers) {
headers = {}
}
if (body) {
headers["content-type"] = "application/json"
headers['content-type'] = 'application/json'
}

const opts = {
Expand All @@ -33,20 +33,25 @@ function request(url: string, method: string = "GET", body?: object, headers?: R
}

type ResWrapped<T> = {
ok: boolean,
data?: T,
ok: boolean
data?: T
err?: string
code: number
}

async function requestWithResponseBody<T>(url: string, method: string = "GET", body?: object, headers?: Record<string, string>): Promise<ResWrapped<T>> {
async function requestWithResponseBody<T>(
url: string,
method: string = 'GET',
body?: object,
headers?: Record<string, string>
): Promise<ResWrapped<T>> {
const res = await request(url, method, body, headers)
const result: ResWrapped<T> = {
ok: res.ok,
code: res.status
}
if (res.ok) {
result.data = await res.json() as T
result.data = (await res.json()) as T
} else {
result.err = await res.text()
}
Expand All @@ -56,7 +61,7 @@ async function requestWithResponseBody<T>(url: string, method: string = "GET", b

async function getAccessToken(): Promise<string> {
if (DateTime.now().plus({ minute: 1 }) > userTokens.access_expires) {
console.log("access token needs a refresh!")
console.log('access token needs a refresh!')
const refreshRes = await RequestService.account.refresh()
if (refreshRes.ok && refreshRes.data) {
userTokens.access_expires = DateTime.now().plus({ minutes: 55 })
Expand All @@ -66,25 +71,30 @@ async function getAccessToken(): Promise<string> {
}
}
if (!userTokens.access) {
actionsExported.logFrontend("Tried to call using an empty token!")
throw new Error("token not set")
actionsExported.logFrontend('Tried to call using an empty token!')
throw new Error('token not set')
}
return userTokens.access
}

async function requestToken(url: string, method: string = "GET", body?: object) {
return await request(url, method, body, { 'authorization': `Bearer ${await getAccessToken()}` })
async function requestToken(url: string, method: string = 'GET', body?: object) {
return await request(url, method, body, { authorization: `Bearer ${await getAccessToken()}` })
}

async function requestTokenBody<T>(url: string, method: string = "GET", body?: object) {
return requestWithResponseBody<T>(url, method, body, { 'authorization': `Bearer ${await getAccessToken()}` })
async function requestTokenBody<T>(url: string, method: string = 'GET', body?: object) {
return requestWithResponseBody<T>(url, method, body, { authorization: `Bearer ${await getAccessToken()}` })
}

export const RequestService = {
account: {
register: (username: string, remotePass: string) => requestWithResponseBody<RegisterRes>(UserEndpoints.Register, "POST", { username, password: remotePass }),
login: (username: string, remotePass: string, code2fa: string) => requestWithResponseBody<LoginRes>(UserEndpoints.Login, "POST", { username, password: remotePass, code: code2fa }),
refresh: () => requestWithResponseBody<RefreshRes>(UserEndpoints.RefreshToken, "POST", undefined, { "authorization": `Bearer ${userTokens.refresh}` }),
register: (username: string, remotePass: string) =>
requestWithResponseBody<RegisterRes>(UserEndpoints.Register, 'POST', { username, password: remotePass }),
login: (username: string, remotePass: string, code2fa: string) =>
requestWithResponseBody<LoginRes>(UserEndpoints.Login, 'POST', { username, password: remotePass, code: code2fa }),
refresh: () =>
requestWithResponseBody<RefreshRes>(UserEndpoints.RefreshToken, 'POST', undefined, {
authorization: `Bearer ${userTokens.refresh}`
}),
logout() {
userTokens.refresh = undefined
userTokens.access = undefined
Expand All @@ -95,18 +105,24 @@ export const RequestService = {
const url = ClipsEndpoints.GetDatabaseFile() + `?token=${await getAccessToken()}`
return url
},
confirm2fa: (code: string, token: string) => requestWithResponseBody<CommonRes>(UserEndpoints.Confirm2FA, "POST", {
code
}, { "authorization": `Bearer ${token}` })
confirm2fa: (code: string, token: string) =>
requestWithResponseBody<CommonRes>(
UserEndpoints.Confirm2FA,
'POST',
{
code
},
{ authorization: `Bearer ${token}` }
)
},
clips: {
add: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, "POST", clip),
upsert: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, "PUT", clip),
update: (clip: { isFavorite: boolean, hash: string }) => requestToken(ClipsEndpoints.CreateUpdate, "PATCH", clip),
delete: (hash: string) => requestToken(ClipsEndpoints.Delete(hash), "DELETE"),
getSince: (time: DateTime) => requestTokenBody<BulkRes>(ClipsEndpoints.GetAllSince(time), "GET"),
getBetween: (start: DateTime, end: DateTime) => requestTokenBody<BulkRes>(ClipsEndpoints.GetInBetween(start, end), "GET"),
getNBefore: (time: DateTime, limit: number) => requestTokenBody<BulkRes>(ClipsEndpoints.GetNBefore(time, limit), "GET"),
deleteAll: () => requestTokenBody<CommonRes>(ClipsEndpoints.DeletAllData(), "DELETE"),
add: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, 'POST', clip),
upsert: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, 'PUT', clip),
update: (clip: { isFavorite: boolean; hash: string }) => requestToken(ClipsEndpoints.CreateUpdate, 'PATCH', clip),
delete: (hash: string) => requestToken(ClipsEndpoints.Delete(hash), 'DELETE'),
getSince: (time: DateTime) => requestTokenBody<BulkRes>(ClipsEndpoints.GetAllSince(time), 'GET'),
getBetween: (start: DateTime, end: DateTime) => requestTokenBody<BulkRes>(ClipsEndpoints.GetInBetween(start, end), 'GET'),
getNBefore: (time: DateTime, limit: number) => requestTokenBody<BulkRes>(ClipsEndpoints.GetNBefore(time, limit), 'GET'),
deleteAll: () => requestTokenBody<CommonRes>(ClipsEndpoints.DeletAllData(), 'DELETE')
}
}
}
3 changes: 1 addition & 2 deletions src/electron/DataModels/DataTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import stringify from 'json-stable-stringify'


// export interface IItemsDb {
// Add(item: IClipboardItemEncrypted): Promise<IClipboardItemEncrypted>
// GetRange(start: number, end: number): Promise<IClipboardItemEncrypted[]>
Expand Down Expand Up @@ -68,7 +67,7 @@ export enum RemoteItemStatus {
}

export interface IClipboardItem extends ItemBase {
content: string;
content: string
created: Date
modified: Date
remoteStatus: RemoteItemStatus
Expand Down
Loading