* @author Bart Visscher * @author Christoph Wurst * @author Hemanth Kumar Veeranki * @author Joas Schilling * @author Michael Göhler * @author Morris Jobke * @author Oliver Salzburg * @author Roeland Jago Douma * @author Thomas Müller * @author Vincent Petry * * @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 * */ namespace OC\Setup; use OC\DB\MySqlTools; use OCP\IDBConnection; use OCP\ILogger; use Doctrine\DBAL\Platforms\MySQL80Platform; class MySQL extends AbstractDatabase { public $dbprettyname = 'MySQL/MariaDB'; public function setupDatabase($username) { //check if the database user has admin right $connection = $this->connect(['dbname' => null]); // detect mb4 $tools = new MySqlTools(); if ($tools->supports4ByteCharset($connection)) { $this->config->setValue('mysql.utf8mb4', true); $connection = $this->connect(['dbname' => null]); } $this->createSpecificUser($username, $connection); //create the database $this->createDatabase($connection); //fill the database if needed $query='select count(*) from information_schema.tables where table_schema=? AND table_name = ?'; $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); $connection->close(); $connection = $this->connect(); try { $connection->connect(); } catch (\Exception $e) { $this->logger->logException($e); throw new \OC\DatabaseSetupException($this->trans->t('MySQL username and/or password not valid'), $this->trans->t('You need to enter details of an existing account.')); } } /** * @param \OC\DB\Connection $connection */ private function createDatabase($connection) { try { $name = $this->dbName; $user = $this->dbUser; //we can't use OC_DB functions here because we need to connect as the administrative user. $characterSet = $this->config->getValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8'; $query = "CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET $characterSet COLLATE ${characterSet}_bin;"; $connection->executeUpdate($query); } catch (\Exception $ex) { $this->logger->logException($ex, [ 'message' => 'Database creation failed.', 'level' => ILogger::ERROR, 'app' => 'mysql.setup', ]); return; } try { //this query will fail if there aren't the right permissions, ignore the error $query="GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `$name` . * TO '$user'"; $connection->executeUpdate($query); } catch (\Exception $ex) { $this->logger->logException($ex, [ 'message' => 'Could not automatically grant privileges, this can be ignored if database user already had privileges.', 'level' => ILogger::DEBUG, 'app' => 'mysql.setup', ]); } } /** * @param IDBConnection $connection * @throws \OC\DatabaseSetupException */ private function createDBUser($connection) { try { $name = $this->dbUser; $password = $this->dbPassword; // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one, // the anonymous user would take precedence when there is one. if ($connection->getDatabasePlatform() instanceof Mysql80Platform) { $query = "CREATE USER '$name'@'localhost' IDENTIFIED WITH mysql_native_password BY '$password'"; $connection->executeUpdate($query); $query = "CREATE USER '$name'@'%' IDENTIFIED WITH mysql_native_password BY '$password'"; $connection->executeUpdate($query); } else { $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; $connection->executeUpdate($query); $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; $connection->executeUpdate($query); } } catch (\Exception $ex) { $this->logger->logException($ex, [ 'message' => 'Database user creation failed.', 'level' => ILogger::ERROR, 'app' => 'mysql.setup', ]); } } /** * @param $username * @param IDBConnection $connection * @return array */ private function createSpecificUser($username, $connection) { try { //user already specified in config $oldUser = $this->config->getValue('dbuser', false); //we don't have a dbuser specified in config if ($this->dbUser !== $oldUser) { //add prefix to the admin username to prevent collisions $adminUser = substr('oc_' . $username, 0, 16); $i = 1; while (true) { //this should be enough to check for admin rights in mysql $query = 'SELECT user FROM mysql.user WHERE user=?'; $result = $connection->executeQuery($query, [$adminUser]); //current dbuser has admin rights if ($result) { $data = $result->fetchAll(); //new dbuser does not exist if (count($data) === 0) { //use the admin login data for the new database user $this->dbUser = $adminUser; //create a random password so we don't need to store the admin password in the config file $this->dbPassword = $this->random->generate(30); $this->createDBUser($connection); break; } else { //repeat with different username $length = strlen((string)$i); $adminUser = substr('oc_' . $username, 0, 16 - $length) . $i; $i++; } } else { break; } } } } catch (\Exception $ex) { $this->logger->logException($ex, [ 'message' => 'Can not create a new MySQL user, will continue with the provided user.', 'level' => ILogger::INFO, 'app' => 'mysql.setup', ]); } $this->config->setValues([ 'dbuser' => $this->dbUser, 'dbpassword' => $this->dbPassword, ]); } } '/vaadin-framework.git/tree/server/src/main/java/com/vaadin/server/BootstrapListener.java?id=a1d5d964815cd2acc7516be73d0649c87070e3fd'>treecommitdiffstats
blob: b5408610be3937298c8e890ee6bb00543caf01a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.vaadin.server;

import java.io.Serializable;
import java.util.EventListener;

import javax.portlet.RenderResponse;

/**
 * Event listener notified when the bootstrap HTML is about to be generated and
 * send to the client. The bootstrap HTML is first constructed as an in-memory
 * DOM representation which registered listeners can modify before the final
 * HTML is generated.
 *
 * @author Vaadin Ltd
 * @since 7.0.0
 */
public interface BootstrapListener extends EventListener, Serializable {
    /**
     * Lets this listener make changes to the fragment that makes up the actual
     * Vaadin application. In a typical Servlet deployment, this is the contents
     * of the HTML body tag. In a typical Portlet deployment, this is the HTML
     * that will be returned in a {@link RenderResponse}.
     *
     * @param response
     *            the bootstrap response that can modified to cause changes in
     *            the generated HTML.
     */
    public void modifyBootstrapFragment(BootstrapFragmentResponse response);

    /**
     * Lets this listener make changes to the overall HTML document that will be
     * used as the initial HTML page in a typical Servlet deployment as well as
     * the HTTP headers in the response serving the initial HTML. In cases where
     * a full HTML document is not generated, this method will not be invoked.
     * <p>
     * If a full page is being generated, this method is invoked after
     * {@link #modifyBootstrapFragment(BootstrapFragmentResponse)} has been
     * invoked for all registered listeners.
     *
     * @param response
     *            the bootstrap response that can be modified to cause change in
     *            the generate HTML and in the HTTP headers of the response.
     */
    public void modifyBootstrapPage(BootstrapPageResponse response);
}