Skip to content
This repository was archived by the owner on Dec 27, 2022. It is now read-only.
Open
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
2 changes: 2 additions & 0 deletions app/background-process.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as settings from './background-process/dbs/settings'
import * as sitedata from './background-process/dbs/sitedata'
import * as profileDataDb from './background-process/dbs/profile-data-db'
import * as bookmarksDb from './background-process/dbs/bookmarks'
import * as servicesDb from './background-process/dbs/services'

import * as beakerProtocol from './background-process/protocols/beaker'
import * as beakerFaviconProtocol from './background-process/protocols/beaker-favicon'
Expand Down Expand Up @@ -71,6 +72,7 @@ app.on('ready', async function () {
archives.setup()
settings.setup()
sitedata.setup()
await servicesDb.setup()
// TEMP can probably remove this in 2018 or so -prf
bookmarksDb.fixOldBookmarks()

Expand Down
221 changes: 221 additions & 0 deletions app/background-process/dbs/services.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import { app } from 'electron'
import sqlite3 from 'sqlite3'
import path from 'path'
import assert from 'assert'
import _keyBy from 'lodash.keyby'
import {parse as parseURL} from 'url'
import { cbPromise } from '../../lib/functions'
import {toOrigin} from '../../lib/bg/services'
import { setupSqliteDB } from '../../lib/bg/db'

// globals
// =
var db
var migrations
var setupPromise

// exported methods
// =

export function setup () {
// open database
var dbPath = path.join(app.getPath('userData'), 'Services')
db = new sqlite3.Database(dbPath)
setupPromise = setupSqliteDB(db, {migrations}, '[SERVICES]')
}

export async function addService (origin, psaDoc = null) {
await setupPromise
assert(origin && typeof origin === 'string', 'Origin must be a string')
origin = toOrigin(origin)

// update service records
await cbPromise(cb => {
var title = psaDoc && typeof psaDoc.title === 'string' ? psaDoc.title : ''
var description = psaDoc && typeof psaDoc.description === 'string' ? psaDoc.description : ''
var createdAt = Date.now()
db.run(
`UPDATE services SET title=?, description=? WHERE origin=?`,
[title, description, origin],
cb
)
db.run(
`INSERT OR IGNORE INTO services (origin, title, description, createdAt) VALUES (?, ?, ?, ?)`,
[origin, title, description, createdAt],
cb
)
})

// remove any existing links
await cbPromise(cb => db.run(`DELETE FROM links WHERE origin = ?`, [origin], cb))

// add new links
if (psaDoc && psaDoc.links && Array.isArray(psaDoc.links)) {
// add one link per rel type
var links = []
psaDoc.links.forEach(link => {
if (!(link && typeof link === 'object' && typeof link.href === 'string' && typeof link.rel === 'string')) {
return
}
var {rel, href, title} = link
rel.split(' ').forEach(rel => links.push({rel, href, title}))
})

// insert values
await Promise.all(links.map(link => cbPromise(cb => {
var {rel, href, title} = link
title = typeof title === 'string' ? title : ''
db.run(
`INSERT INTO links (origin, rel, href, title) VALUES (?, ?, ?, ?)`,
[origin, rel, href, title],
cb
)
})))
}
}

export async function removeService (origin) {
await setupPromise
assert(origin && typeof origin === 'string', 'Origin must be a string')
origin = toOrigin(origin)
await cbPromise(cb => db.run(`DELETE FROM services WHERE origin = ?`, [origin], cb))
}

export async function addAccount (origin, username, password) {
await setupPromise
assert(origin && typeof origin === 'string', 'Origin must be a string')
assert(username && typeof username === 'string', 'Username must be a string')
assert(password && typeof password === 'string', 'Password must be a string')
origin = toOrigin(origin)

// delete existing account
await cbPromise(cb => db.run(`DELETE FROM accounts WHERE origin = ? AND username = ?`, [origin, username], cb))

// add new account
await cbPromise(cb => db.run(`INSERT INTO accounts (origin, username, password) VALUES (?, ?, ?)`, [origin, username, password], cb))
}

export async function removeAccount (origin, username) {
await setupPromise
assert(origin && typeof origin === 'string', 'Origin must be a string')
assert(username && typeof username === 'string', 'Username must be a string')
origin = toOrigin(origin)
await cbPromise(cb => db.run(`DELETE FROM accounts WHERE origin = ? AND username = ?`, [origin, username], cb))
}

export async function getService (origin) {
var services = await listServices({origin})
return Object.values(services)[0]
}

export async function getAccount (origin, username) {
await setupPromise
origin = toOrigin(origin)
var query = 'SELECT username, password, origin FROM accounts WHERE origin = ? AND username = ?'
return cbPromise(cb => db.get(query, [origin, username], cb))
}

export async function listServices ({origin} = {}) {
await setupPromise
if (origin) {
origin = toOrigin(origin)
}

// construct query
var where = ['1=1']
var params = []
if (origin) {
where.push('origin = ?')
params.push(origin)
}
where = where.join(' AND ')

// run query
var query = `
SELECT origin, title, description, createdAt
FROM services
WHERE ${where}
`
var services = await cbPromise(cb => db.all(query, params, cb))

// get links on each
await Promise.all(services.map(async (service) => {
service.links = await listServiceLinks(service.origin)
service.accounts = await listServiceAccounts(service.origin)
}))

return _keyBy(services, 'origin') // return as an object
}

export async function listAccounts ({api} = {}) {
await setupPromise

// construct query
var join = ''
var where = ['1=1']
var params = []
if (api) {
where.push('links.rel = ?')
params.push(api)
join = 'LEFT JOIN links ON links.origin = accounts.origin'
}
where = where.join(' AND ')

// run query
var query = `
SELECT accounts.username, accounts.origin
FROM accounts
${join}
WHERE ${where}
`
return cbPromise(cb => db.all(query, params, cb))
}

export async function listServiceLinks (origin) {
await setupPromise
origin = toOrigin(origin)
var query = 'SELECT rel, title, href FROM links WHERE origin = ?'
return cbPromise(cb => db.all(query, [origin], cb))
}

export async function listServiceAccounts (origin) {
await setupPromise
origin = toOrigin(origin)
var query = 'SELECT username FROM accounts WHERE origin = ?'
return cbPromise(cb => db.all(query, [origin], cb))
}

// internal methods
// =

migrations = [
// version 1
function (cb) {
db.exec(`
CREATE TABLE services (
origin TEXT PRIMARY KEY,
title TEXT,
description TEXT,
createdAt INTEGER
);
CREATE TABLE accounts (
origin TEXT,
username TEXT,
password TEXT,
createdAt INTEGER,

FOREIGN KEY (origin) REFERENCES services (origin) ON DELETE CASCADE
);
CREATE TABLE links (
origin TEXT,
rel TEXT,
title TEXT,
href TEXT,

FOREIGN KEY (origin) REFERENCES services (origin) ON DELETE CASCADE
);

PRAGMA user_version = 1;
`, cb)
}
]
2 changes: 1 addition & 1 deletion app/background-process/debug-logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function setup () {
let folderPath = process.env.beaker_user_data_path || app.getPath('userData')
logFilePath = joinPath(folderPath, 'debug.log')
console.log('Logfile:', logFilePath)
debug.enable('dat,datgc,dat-dns,dat-serve,dns-discovery,discovery-channel,discovery-swarm,beaker,beaker-sqlite,beaker-analytics')
debug.enable('dat,datgc,dat-dns,dat-serve,dns-discovery,discovery-channel,discovery-swarm,beaker,beaker-sqlite,beaker-analytics,beaker-service')
debug.overrideUseColors()

logFileWriteStream = fs.createWriteStream(logFilePath)
Expand Down
Loading