owncloud/core

View on GitHub
apps/federation/lib/DbHandler.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
/**
 * @author Björn Schießle <bjoern@schiessle.org>
 * @author Thomas Müller <thomas.mueller@tmit.eu>
 *
 * @copyright Copyright (c) 2018, ownCloud GmbH
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

namespace OCA\Federation;

use OC\Files\Filesystem;
use OC\HintException;
use OCP\IDBConnection;
use OCP\IL10N;

/**
 * Class DbHandler
 *
 * handles all database calls for the federation app
 *
 * @group DB
 * @package OCA\Federation
 */
class DbHandler {
    /** @var  IDBConnection */
    private $connection;

    /** @var  IL10N */
    private $il10n;

    /** @var string  */
    private $dbTable = 'trusted_servers';

    /**
     * @param IDBConnection $connection
     * @param IL10N $il10n
     */
    public function __construct(
        IDBConnection $connection,
        IL10N $il10n
    ) {
        $this->connection = $connection;
        $this->il10n = $il10n;
    }

    /**
     * add server to the list of trusted ownCloud servers
     *
     * @param string $url
     * @return int
     * @throws HintException
     */
    public function addServer($url) {
        $hash = $this->hash($url);
        $url = \rtrim($url, '/');
        $query = $this->connection->getQueryBuilder();
        $query->insert($this->dbTable)
            ->values(
                [
                    'url' =>  $query->createParameter('url'),
                    'url_hash' => $query->createParameter('url_hash'),
                ]
            )
            ->setParameter('url', $url)
            ->setParameter('url_hash', $hash);

        $result = $query->execute();

        if ($result) {
            return (int)$this->connection->lastInsertId('*PREFIX*'.$this->dbTable);
        } else {
            $message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url;
            $message_t = $this->il10n->t('Could not add server');
            throw new HintException($message, $message_t);
        }
    }

    /**
     * remove server from the list of trusted ownCloud servers
     *
     * @param int $id
     */
    public function removeServer($id) {
        $query = $this->connection->getQueryBuilder();
        $query->delete($this->dbTable)
            ->where($query->expr()->eq('id', $query->createParameter('id')))
            ->setParameter('id', $id);
        $query->execute();
    }

    /**
     * get trusted server with given ID
     *
     * @param int $id
     * @return array
     * @throws \Exception
     */
    public function getServerById($id) {
        $query = $this->connection->getQueryBuilder();
        $query->select('*')->from($this->dbTable)
            ->where($query->expr()->eq('id', $query->createParameter('id')))
            ->setParameter('id', $id);
        $query->execute();
        $result = $query->execute()->fetchAll();

        if (empty($result)) {
            throw new \Exception('No Server found with ID: ' . $id);
        }

        return $result[0];
    }

    /**
     * get all trusted servers
     *
     * @return array
     */
    public function getAllServer() {
        $query = $this->connection->getQueryBuilder();
        $query->select(['url', 'url_hash', 'id', 'status', 'shared_secret', 'sync_token'])->from($this->dbTable);
        $result = $query->execute()->fetchAll();
        return $result;
    }

    /**
     * check if server already exists in the database table
     *
     * @param string $url
     * @return bool
     */
    public function serverExists($url) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->select('url')->from($this->dbTable)
            ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
            ->setParameter('url_hash', $hash);
        $result = $query->execute()->fetchAll();

        return !empty($result);
    }

    /**
     * write token to database. Token is used to exchange the secret
     *
     * @param string $url
     * @param string $token
     */
    public function addToken($url, $token) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->update($this->dbTable)
            ->set('token', $query->createParameter('token'))
            ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
            ->setParameter('url_hash', $hash)
            ->setParameter('token', $token);
        $query->execute();
    }

    /**
     * get token stored in database
     *
     * @param string $url
     * @return string
     * @throws \Exception
     */
    public function getToken($url) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->select('token')->from($this->dbTable)
            ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
            ->setParameter('url_hash', $hash);

        $result = $query->execute()->fetch();

        if (!isset($result['token'])) {
            throw new \Exception('No token found for: ' . $url);
        }

        return $result['token'];
    }

    /**
     * add shared Secret to database
     *
     * @param string $url
     * @param string $sharedSecret
     */
    public function addSharedSecret($url, $sharedSecret) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->update($this->dbTable)
            ->set('shared_secret', $query->createParameter('sharedSecret'))
            ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
            ->setParameter('url_hash', $hash)
            ->setParameter('sharedSecret', $sharedSecret);
        $query->execute();
    }

    /**
     * get shared secret from database
     *
     * @param string $url
     * @return string
     */
    public function getSharedSecret($url) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->select('shared_secret')->from($this->dbTable)
            ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
            ->setParameter('url_hash', $hash);

        $result = $query->execute()->fetch();
        return $result['shared_secret'];
    }

    /**
     * set server status
     *
     * @param string $url
     * @param int $status
     * @param string|null $token
     */
    public function setServerStatus($url, $status, $token = null) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->update($this->dbTable)
                ->set('status', $query->createNamedParameter($status))
                ->where($query->expr()->eq('url_hash', $query->createNamedParameter($hash)));
        if ($token !== null) {
            $query->set('sync_token', $query->createNamedParameter($token));
        }
        $query->execute();
    }

    /**
     * get server status
     *
     * @param string $url
     * @return int
     */
    public function getServerStatus($url) {
        $hash = $this->hash($url);
        $query = $this->connection->getQueryBuilder();
        $query->select('status')->from($this->dbTable)
                ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
                ->setParameter('url_hash', $hash);

        $result = $query->execute()->fetch();
        return (int)$result['status'];
    }

    /**
     * create hash from URL
     *
     * @param string $url
     * @return string
     */
    protected function hash($url) {
        $normalized = $this->normalizeUrl($url);
        return \sha1($normalized);
    }

    /**
     * normalize URL, used to create the sha1 hash
     *
     * @param string $url
     * @return string
     */
    protected function normalizeUrl($url) {
        $normalized = $url;

        if (\strpos($url, 'https://') === 0) {
            $normalized = \substr($url, \strlen('https://'));
        } elseif (\strpos($url, 'http://') === 0) {
            $normalized = \substr($url, \strlen('http://'));
        }

        $normalized = Filesystem::normalizePath($normalized);
        $normalized = \trim($normalized, '/');

        return $normalized;
    }

    /**
     * @param $username
     * @param $password
     * @return bool
     */
    public function auth($username, $password) {
        if ($username !== 'system') {
            return false;
        }
        $query = $this->connection->getQueryBuilder();
        $query->select('url')->from($this->dbTable)
                ->where($query->expr()->eq('shared_secret', $query->createNamedParameter($password)));

        $result = $query->execute()->fetch();
        return !empty($result);
    }
}