diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-02-07 01:36:13 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-02-07 01:36:13 +0100 |
commit | 95b20e17b97de1f05392d0c394a5efdc590311a9 (patch) | |
tree | cdfbefec201c0e05668353fc87c80669dbe66215 /nixops/modules/websites/tools | |
parent | 609c29615905e2bc5628a164cea2c28ec70d5d35 (diff) | |
download | Nix-95b20e17b97de1f05392d0c394a5efdc590311a9.tar.gz Nix-95b20e17b97de1f05392d0c394a5efdc590311a9.tar.zst Nix-95b20e17b97de1f05392d0c394a5efdc590311a9.zip |
Add shaarli website
Diffstat (limited to 'nixops/modules/websites/tools')
-rw-r--r-- | nixops/modules/websites/tools/tools/default.nix | 9 | ||||
-rw-r--r-- | nixops/modules/websites/tools/tools/shaarli.nix | 86 | ||||
-rw-r--r-- | nixops/modules/websites/tools/tools/shaarli_ldap.patch | 420 |
3 files changed, 514 insertions, 1 deletions
diff --git a/nixops/modules/websites/tools/tools/default.nix b/nixops/modules/websites/tools/tools/default.nix index 333ffb0..41f47a3 100644 --- a/nixops/modules/websites/tools/tools/default.nix +++ b/nixops/modules/websites/tools/tools/default.nix | |||
@@ -18,6 +18,9 @@ let | |||
18 | inherit (mylibs) fetchedGithub; | 18 | inherit (mylibs) fetchedGithub; |
19 | env = myconfig.env.tools.rompr; | 19 | env = myconfig.env.tools.rompr; |
20 | }; | 20 | }; |
21 | shaarli = pkgs.callPackage ./shaarli.nix { | ||
22 | env = myconfig.env.tools.shaarli; | ||
23 | }; | ||
21 | 24 | ||
22 | cfg = config.services.myWebsites.tools.tools; | 25 | cfg = config.services.myWebsites.tools.tools; |
23 | in { | 26 | in { |
@@ -35,7 +38,8 @@ in { | |||
35 | ++ roundcubemail.apache.modules | 38 | ++ roundcubemail.apache.modules |
36 | ++ wallabag.apache.modules | 39 | ++ wallabag.apache.modules |
37 | ++ yourls.apache.modules | 40 | ++ yourls.apache.modules |
38 | ++ rompr.apache.modules; | 41 | ++ rompr.apache.modules |
42 | ++ shaarli.apache.modules; | ||
39 | 43 | ||
40 | services.ympd = ympd.config // { enable = true; }; | 44 | services.ympd = ympd.config // { enable = true; }; |
41 | 45 | ||
@@ -51,6 +55,7 @@ in { | |||
51 | wallabag.apache.vhostConf | 55 | wallabag.apache.vhostConf |
52 | yourls.apache.vhostConf | 56 | yourls.apache.vhostConf |
53 | rompr.apache.vhostConf | 57 | rompr.apache.vhostConf |
58 | shaarli.apache.vhostConf | ||
54 | ]; | 59 | ]; |
55 | }; | 60 | }; |
56 | 61 | ||
@@ -61,6 +66,7 @@ in { | |||
61 | wallabag = wallabag.phpFpm.pool; | 66 | wallabag = wallabag.phpFpm.pool; |
62 | yourls = yourls.phpFpm.pool; | 67 | yourls = yourls.phpFpm.pool; |
63 | rompr = rompr.phpFpm.pool; | 68 | rompr = rompr.phpFpm.pool; |
69 | shaarli = shaarli.phpFpm.pool; | ||
64 | }; | 70 | }; |
65 | 71 | ||
66 | system.activationScripts = { | 72 | system.activationScripts = { |
@@ -69,6 +75,7 @@ in { | |||
69 | wallabag = wallabag.activationScript; | 75 | wallabag = wallabag.activationScript; |
70 | yourls = yourls.activationScript; | 76 | yourls = yourls.activationScript; |
71 | rompr = rompr.activationScript; | 77 | rompr = rompr.activationScript; |
78 | shaarli = shaarli.activationScript; | ||
72 | }; | 79 | }; |
73 | 80 | ||
74 | systemd.services.tt-rss = { | 81 | systemd.services.tt-rss = { |
diff --git a/nixops/modules/websites/tools/tools/shaarli.nix b/nixops/modules/websites/tools/tools/shaarli.nix new file mode 100644 index 0000000..9f3779f --- /dev/null +++ b/nixops/modules/websites/tools/tools/shaarli.nix | |||
@@ -0,0 +1,86 @@ | |||
1 | { lib, env, stdenv, fetchurl }: | ||
2 | |||
3 | let | ||
4 | varDir = "/var/lib/shaarli"; | ||
5 | shaarli = stdenv.mkDerivation rec { | ||
6 | name = "shaarli-${version}"; | ||
7 | version = "0.10.2"; | ||
8 | |||
9 | src = fetchurl { | ||
10 | url = "https://github.com/shaarli/Shaarli/releases/download/v${version}/shaarli-v${version}-full.tar.gz"; | ||
11 | sha256 = "0h8sspj7siy3vgpi2i3gdrjcr5935fr4dfwq2zwd70sjx2sh9s78"; | ||
12 | }; | ||
13 | |||
14 | outputs = [ "out" "doc" ]; | ||
15 | |||
16 | patches = [ ./shaarli_ldap.patch ]; | ||
17 | |||
18 | installPhase = '' | ||
19 | rm -r {cache,pagecache,tmp,data}/ | ||
20 | ln -sf ../../../..${varDir}/{cache,pagecache,tmp,data} . | ||
21 | mkdir -p $doc/share/doc | ||
22 | mv doc/ $doc/share/doc/shaarli | ||
23 | mkdir $out/ | ||
24 | cp -R ./* $out | ||
25 | cp .htaccess $out/ | ||
26 | ''; | ||
27 | |||
28 | meta = with stdenv.lib; { | ||
29 | description = "The personal, minimalist, super-fast, database free, bookmarking service"; | ||
30 | license = licenses.gpl3Plus; | ||
31 | homepage = https://github.com/shaarli/Shaarli; | ||
32 | maintainers = with maintainers; [ schneefux ]; | ||
33 | platforms = platforms.all; | ||
34 | }; | ||
35 | }; | ||
36 | in rec { | ||
37 | activationScript = '' | ||
38 | install -m 0755 -o ${apache.user} -g ${apache.group} -d ${varDir} \ | ||
39 | ${varDir}/cache ${varDir}/pagecache ${varDir}/tmp ${varDir}/data \ | ||
40 | ${varDir}/phpSessions | ||
41 | ''; | ||
42 | webRoot = shaarli; | ||
43 | apache = { | ||
44 | user = "wwwrun"; | ||
45 | group = "wwwrun"; | ||
46 | modules = [ "proxy_fcgi" "rewrite" "env" ]; | ||
47 | vhostConf = '' | ||
48 | Alias /Shaarli "${webRoot}" | ||
49 | |||
50 | <Directory "${webRoot}"> | ||
51 | SetEnv SHAARLI_LDAP_PASSWORD "${env.ldap.password}" | ||
52 | SetEnv SHAARLI_LDAP_DN "${env.ldap.dn}" | ||
53 | SetEnv SHAARLI_LDAP_HOST "ldaps://${env.ldap.host}" | ||
54 | SetEnv SHAARLI_LDAP_BASE "${env.ldap.base}" | ||
55 | SetEnv SHAARLI_LDAP_FILTER "${env.ldap.search}" | ||
56 | |||
57 | DirectoryIndex index.php index.htm index.html | ||
58 | Options Indexes FollowSymLinks MultiViews Includes | ||
59 | AllowOverride All | ||
60 | Require all granted | ||
61 | <FilesMatch "\.php$"> | ||
62 | SetHandler "proxy:unix:${phpFpm.socket}|fcgi://localhost" | ||
63 | </FilesMatch> | ||
64 | </Directory> | ||
65 | ''; | ||
66 | }; | ||
67 | phpFpm = rec { | ||
68 | basedir = builtins.concatStringsSep ":" [ webRoot varDir ]; | ||
69 | socket = "/var/run/phpfpm/shaarli.sock"; | ||
70 | pool = '' | ||
71 | listen = ${socket} | ||
72 | user = ${apache.user} | ||
73 | group = ${apache.group} | ||
74 | listen.owner = ${apache.user} | ||
75 | listen.group = ${apache.group} | ||
76 | pm = ondemand | ||
77 | pm.max_children = 60 | ||
78 | pm.process_idle_timeout = 60 | ||
79 | |||
80 | ; Needed to avoid clashes in browser cookies (same domain) | ||
81 | php_value[session.name] = ShaarliPHPSESSID | ||
82 | php_admin_value[open_basedir] = "${basedir}:/tmp" | ||
83 | php_admin_value[session.save_path] = "${varDir}/phpSessions" | ||
84 | ''; | ||
85 | }; | ||
86 | } | ||
diff --git a/nixops/modules/websites/tools/tools/shaarli_ldap.patch b/nixops/modules/websites/tools/tools/shaarli_ldap.patch new file mode 100644 index 0000000..9c7315a --- /dev/null +++ b/nixops/modules/websites/tools/tools/shaarli_ldap.patch | |||
@@ -0,0 +1,420 @@ | |||
1 | commit bc82ebfd779b8641dadd6787f51639ea9105c3e8 | ||
2 | Author: Ismaël Bouya <ismael.bouya@normalesup.org> | ||
3 | Date: Sun Feb 3 20:58:18 2019 +0100 | ||
4 | |||
5 | Add ldap connection | ||
6 | |||
7 | diff --git a/.htaccess b/.htaccess | ||
8 | index 4c00427..5acd708 100644 | ||
9 | --- a/.htaccess | ||
10 | +++ b/.htaccess | ||
11 | @@ -6,10 +6,23 @@ RewriteEngine On | ||
12 | # Prevent accessing subdirectories not managed by SCM | ||
13 | RewriteRule ^(.git|doxygen|vendor) - [F] | ||
14 | |||
15 | +RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ | ||
16 | +RewriteRule ^(.*) - [E=BASE:%1] | ||
17 | + | ||
18 | +RewriteCond %{ENV:REDIRECT_BASE} (.+) | ||
19 | +RewriteRule .* - [E=BASE:%1] | ||
20 | + | ||
21 | # Forward the "Authorization" HTTP header | ||
22 | RewriteCond %{HTTP:Authorization} ^(.*) | ||
23 | RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] | ||
24 | |||
25 | +RewriteCond %{REQUEST_FILENAME} !-f | ||
26 | +RewriteCond %{REQUEST_FILENAME} !-d | ||
27 | +RewriteRule ^((?!api/)[^/]*)/?(.*)$ $2?%{QUERY_STRING} [E=USERSPACE:$1] | ||
28 | + | ||
29 | +RewriteCond %{ENV:REDIRECT_USERSPACE} (.+) | ||
30 | +RewriteRule .* - [E=USERSPACE:%1] | ||
31 | + | ||
32 | # REST API | ||
33 | RewriteCond %{REQUEST_FILENAME} !-f | ||
34 | RewriteCond %{REQUEST_FILENAME} !-d | ||
35 | diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php | ||
36 | index 911873a..f21a1ef 100644 | ||
37 | --- a/application/ApplicationUtils.php | ||
38 | +++ b/application/ApplicationUtils.php | ||
39 | @@ -191,6 +191,9 @@ public static function checkResourcePermissions($conf) | ||
40 | $conf->get('resource.page_cache'), | ||
41 | $conf->get('resource.raintpl_tmp'), | ||
42 | ) as $path) { | ||
43 | + if (! is_dir($path)) { | ||
44 | + mkdir($path, 0755, true); | ||
45 | + } | ||
46 | if (! is_readable(realpath($path))) { | ||
47 | $errors[] = '"'.$path.'" '. t('directory is not readable'); | ||
48 | } | ||
49 | diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php | ||
50 | index 32aaea4..99efc15 100644 | ||
51 | --- a/application/config/ConfigManager.php | ||
52 | +++ b/application/config/ConfigManager.php | ||
53 | @@ -21,6 +21,11 @@ class ConfigManager | ||
54 | |||
55 | public static $DEFAULT_PLUGINS = array('qrcode'); | ||
56 | |||
57 | + /** | ||
58 | + * @var string User space. | ||
59 | + */ | ||
60 | + protected $userSpace; | ||
61 | + | ||
62 | /** | ||
63 | * @var string Config folder. | ||
64 | */ | ||
65 | @@ -41,12 +46,36 @@ class ConfigManager | ||
66 | * | ||
67 | * @param string $configFile Configuration file path without extension. | ||
68 | */ | ||
69 | - public function __construct($configFile = 'data/config') | ||
70 | + public function __construct($configFile = null, $userSpace = null) | ||
71 | { | ||
72 | - $this->configFile = $configFile; | ||
73 | + $this->userSpace = $this->findLDAPUser($userSpace); | ||
74 | + if ($configFile !== null) { | ||
75 | + $this->configFile = $configFile; | ||
76 | + } else { | ||
77 | + $this->configFile = ($this->userSpace === null) ? 'data/config' : 'data/' . $this->userSpace . '/config'; | ||
78 | + } | ||
79 | $this->initialize(); | ||
80 | } | ||
81 | |||
82 | + public function findLDAPUser($login, $password = null) { | ||
83 | + $connect = ldap_connect(getenv('SHAARLI_LDAP_HOST')); | ||
84 | + ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3); | ||
85 | + if (!$connect || !ldap_bind($connect, getenv('SHAARLI_LDAP_DN'), getenv('SHAARLI_LDAP_PASSWORD'))) { | ||
86 | + return false; | ||
87 | + } | ||
88 | + | ||
89 | + $search_query = str_replace('%login%', ldap_escape($login), getenv('SHAARLI_LDAP_FILTER')); | ||
90 | + | ||
91 | + $search = ldap_search($connect, getenv('SHAARLI_LDAP_BASE'), $search_query); | ||
92 | + $info = ldap_get_entries($connect, $search); | ||
93 | + | ||
94 | + if (ldap_count_entries($connect, $search) == 1 && (is_null($password) || ldap_bind($connect, $info[0]["dn"], $password))) { | ||
95 | + return $login; | ||
96 | + } else { | ||
97 | + return null; | ||
98 | + } | ||
99 | + } | ||
100 | + | ||
101 | /** | ||
102 | * Reset the ConfigManager instance. | ||
103 | */ | ||
104 | @@ -269,6 +298,16 @@ public function getConfigFileExt() | ||
105 | return $this->configFile . $this->configIO->getExtension(); | ||
106 | } | ||
107 | |||
108 | + /** | ||
109 | + * Get the current userspace. | ||
110 | + * | ||
111 | + * @return mixed User space. | ||
112 | + */ | ||
113 | + public function getUserSpace() | ||
114 | + { | ||
115 | + return $this->userSpace; | ||
116 | + } | ||
117 | + | ||
118 | /** | ||
119 | * Recursive function which find asked setting in the loaded config. | ||
120 | * | ||
121 | @@ -342,19 +381,31 @@ protected static function removeConfig($settings, &$conf) | ||
122 | */ | ||
123 | protected function setDefaultValues() | ||
124 | { | ||
125 | - $this->setEmpty('resource.data_dir', 'data'); | ||
126 | - $this->setEmpty('resource.config', 'data/config.php'); | ||
127 | - $this->setEmpty('resource.datastore', 'data/datastore.php'); | ||
128 | - $this->setEmpty('resource.ban_file', 'data/ipbans.php'); | ||
129 | - $this->setEmpty('resource.updates', 'data/updates.txt'); | ||
130 | - $this->setEmpty('resource.log', 'data/log.txt'); | ||
131 | - $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); | ||
132 | - $this->setEmpty('resource.history', 'data/history.php'); | ||
133 | + if ($this->userSpace === null) { | ||
134 | + $data = 'data'; | ||
135 | + $tmp = 'tmp'; | ||
136 | + $cache = 'cache'; | ||
137 | + $pagecache = 'pagecache'; | ||
138 | + } else { | ||
139 | + $data = 'data/' . ($this->userSpace); | ||
140 | + $tmp = 'tmp/' . ($this->userSpace); | ||
141 | + $cache = 'cache/' . ($this->userSpace); | ||
142 | + $pagecache = 'pagecache/' . ($this->userSpace); | ||
143 | + } | ||
144 | + | ||
145 | + $this->setEmpty('resource.data_dir', $data); | ||
146 | + $this->setEmpty('resource.config', $data . '/config.php'); | ||
147 | + $this->setEmpty('resource.datastore', $data . '/datastore.php'); | ||
148 | + $this->setEmpty('resource.ban_file', $data . '/ipbans.php'); | ||
149 | + $this->setEmpty('resource.updates', $data . '/updates.txt'); | ||
150 | + $this->setEmpty('resource.log', $data . '/log.txt'); | ||
151 | + $this->setEmpty('resource.update_check', $data . '/lastupdatecheck.txt'); | ||
152 | + $this->setEmpty('resource.history', $data . '/history.php'); | ||
153 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); | ||
154 | $this->setEmpty('resource.theme', 'default'); | ||
155 | - $this->setEmpty('resource.raintpl_tmp', 'tmp/'); | ||
156 | - $this->setEmpty('resource.thumbnails_cache', 'cache'); | ||
157 | - $this->setEmpty('resource.page_cache', 'pagecache'); | ||
158 | + $this->setEmpty('resource.raintpl_tmp', $tmp); | ||
159 | + $this->setEmpty('resource.thumbnails_cache', $cache); | ||
160 | + $this->setEmpty('resource.page_cache', $pagecache); | ||
161 | |||
162 | $this->setEmpty('security.ban_after', 4); | ||
163 | $this->setEmpty('security.ban_duration', 1800); | ||
164 | diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php | ||
165 | index d6784d6..bdfaca7 100644 | ||
166 | --- a/application/security/LoginManager.php | ||
167 | +++ b/application/security/LoginManager.php | ||
168 | @@ -32,6 +32,9 @@ class LoginManager | ||
169 | /** @var string User sign-in token depending on remote IP and credentials */ | ||
170 | protected $staySignedInToken = ''; | ||
171 | |||
172 | + protected $lastErrorReason = ''; | ||
173 | + protected $lastErrorIsBanishable = false; | ||
174 | + | ||
175 | /** | ||
176 | * Constructor | ||
177 | * | ||
178 | @@ -83,7 +86,7 @@ public function getStaySignedInToken() | ||
179 | */ | ||
180 | public function checkLoginState($cookie, $clientIpId) | ||
181 | { | ||
182 | - if (! $this->configManager->exists('credentials.login')) { | ||
183 | + if (! $this->configManager->exists('credentials.login') || (isset($_SESSION['username']) && $_SESSION['username'] && $this->configManager->get('credentials.login') !== $_SESSION['username'])) { | ||
184 | // Shaarli is not configured yet | ||
185 | $this->isLoggedIn = false; | ||
186 | return; | ||
187 | @@ -133,20 +136,40 @@ public function isLoggedIn() | ||
188 | */ | ||
189 | public function checkCredentials($remoteIp, $clientIpId, $login, $password) | ||
190 | { | ||
191 | - $hash = sha1($password . $login . $this->configManager->get('credentials.salt')); | ||
192 | + $this->lastErrorIsBanishable = false; | ||
193 | + | ||
194 | + if ($this->configManager->getUserSpace() !== null && $this->configManager->getUserSpace() !== $login) { | ||
195 | + logm($this->configManager->get('resource.log'), | ||
196 | + $remoteIp, | ||
197 | + 'Trying to login to wrong user space'); | ||
198 | + $this->lastErrorReason = 'You’re trying to access the wrong account.'; | ||
199 | + return false; | ||
200 | + } | ||
201 | |||
202 | - if ($login != $this->configManager->get('credentials.login') | ||
203 | - || $hash != $this->configManager->get('credentials.hash') | ||
204 | - ) { | ||
205 | + logm($this->configManager->get('resource.log'), | ||
206 | + $remoteIp, | ||
207 | + 'Trying LDAP connection'); | ||
208 | + $result = $this->configManager->findLDAPUser($login, $password); | ||
209 | + if ($result === false) { | ||
210 | logm( | ||
211 | $this->configManager->get('resource.log'), | ||
212 | $remoteIp, | ||
213 | - 'Login failed for user ' . $login | ||
214 | + 'Impossible to connect to LDAP' | ||
215 | ); | ||
216 | + $this->lastErrorReason = 'Server error.'; | ||
217 | + return false; | ||
218 | + } else if (is_null($result)) { | ||
219 | + logm( | ||
220 | + $this->configManager->get('resource.log'), | ||
221 | + $remoteIp, | ||
222 | + 'Login failed for user ' . $login | ||
223 | + ); | ||
224 | + $this->lastErrorIsBanishable = true; | ||
225 | + $this->lastErrorReason = 'Wrong login/password.'; | ||
226 | return false; | ||
227 | } | ||
228 | |||
229 | - $this->sessionManager->storeLoginInfo($clientIpId); | ||
230 | + $this->sessionManager->storeLoginInfo($clientIpId, $login); | ||
231 | logm( | ||
232 | $this->configManager->get('resource.log'), | ||
233 | $remoteIp, | ||
234 | @@ -187,6 +210,10 @@ protected function writeBanFile() | ||
235 | */ | ||
236 | public function handleFailedLogin($server) | ||
237 | { | ||
238 | + if (!$this->lastErrorIsBanishable) { | ||
239 | + return $this->lastErrorReason ?: 'Error during login.'; | ||
240 | + }; | ||
241 | + | ||
242 | $ip = $server['REMOTE_ADDR']; | ||
243 | $trusted = $this->configManager->get('security.trusted_proxies', []); | ||
244 | |||
245 | @@ -215,6 +242,7 @@ public function handleFailedLogin($server) | ||
246 | ); | ||
247 | } | ||
248 | $this->writeBanFile(); | ||
249 | + return $this->lastErrorReason ?: 'Error during login.'; | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php | ||
254 | index b8b8ab8..5eb4aac 100644 | ||
255 | --- a/application/security/SessionManager.php | ||
256 | +++ b/application/security/SessionManager.php | ||
257 | @@ -111,10 +111,10 @@ public static function checkId($sessionId) | ||
258 | * | ||
259 | * @param string $clientIpId Client IP address identifier | ||
260 | */ | ||
261 | - public function storeLoginInfo($clientIpId) | ||
262 | + public function storeLoginInfo($clientIpId, $login = null) | ||
263 | { | ||
264 | $this->session['ip'] = $clientIpId; | ||
265 | - $this->session['username'] = $this->conf->get('credentials.login'); | ||
266 | + $this->session['username'] = $login ?: $this->conf->get('credentials.login'); | ||
267 | $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); | ||
268 | } | ||
269 | |||
270 | diff --git a/index.php b/index.php | ||
271 | index 4b86a3e..85376e8 100644 | ||
272 | --- a/index.php | ||
273 | +++ b/index.php | ||
274 | @@ -121,7 +121,27 @@ | ||
275 | $_COOKIE['shaarli'] = session_id(); | ||
276 | } | ||
277 | |||
278 | -$conf = new ConfigManager(); | ||
279 | +$folderBase = getenv("BASE"); | ||
280 | + | ||
281 | +if (getenv("USERSPACE")) { | ||
282 | + if (isset($_GET["do"]) && $_GET["do"] == "login") { | ||
283 | + header("Location: $folderBase/?do=login"); | ||
284 | + exit; | ||
285 | + } | ||
286 | + $userspace = preg_replace("/[^-_A-Za-z0-9]/", '', getenv("USERSPACE")); | ||
287 | +} else if (isset($_SESSION["username"]) && $_SESSION["username"]) { | ||
288 | + header("Location: " . $folderBase . "/" . $_SESSION["username"] . "?"); | ||
289 | + exit; | ||
290 | +} else if (!isset($_GET["do"]) || $_GET["do"] != "login") { | ||
291 | + header("Location: $folderBase/?do=login"); | ||
292 | + exit; | ||
293 | +} | ||
294 | + | ||
295 | +if (isset($userspace)) { | ||
296 | + $conf = new ConfigManager(null, $userspace); | ||
297 | +} else { | ||
298 | + $conf = new ConfigManager(); | ||
299 | +} | ||
300 | $sessionManager = new SessionManager($_SESSION, $conf); | ||
301 | $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager); | ||
302 | $loginManager->generateStaySignedInToken($_SERVER['REMOTE_ADDR']); | ||
303 | @@ -175,7 +195,7 @@ | ||
304 | } | ||
305 | |||
306 | // Display the installation form if no existing config is found | ||
307 | - install($conf, $sessionManager, $loginManager); | ||
308 | + install($conf, $sessionManager, $loginManager, $userspace); | ||
309 | } | ||
310 | |||
311 | $loginManager->checkLoginState($_COOKIE, $clientIpId); | ||
312 | @@ -205,6 +225,7 @@ function isLoggedIn() | ||
313 | && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password']) | ||
314 | ) { | ||
315 | $loginManager->handleSuccessfulLogin($_SERVER); | ||
316 | + $userspace = $_POST['login']; | ||
317 | |||
318 | $cookiedir = ''; | ||
319 | if (dirname($_SERVER['SCRIPT_NAME']) != '/') { | ||
320 | @@ -241,25 +262,25 @@ function isLoggedIn() | ||
321 | $uri .= '&'.$param.'='.urlencode($_GET[$param]); | ||
322 | } | ||
323 | } | ||
324 | - header('Location: '. $uri); | ||
325 | + header('Location: '. $userspace . $uri); | ||
326 | exit; | ||
327 | } | ||
328 | |||
329 | if (isset($_GET['edit_link'])) { | ||
330 | - header('Location: ?edit_link='. escape($_GET['edit_link'])); | ||
331 | + header('Location: ' . $userspace . '?edit_link='. escape($_GET['edit_link'])); | ||
332 | exit; | ||
333 | } | ||
334 | |||
335 | if (isset($_POST['returnurl'])) { | ||
336 | // Prevent loops over login screen. | ||
337 | if (strpos($_POST['returnurl'], 'do=login') === false) { | ||
338 | - header('Location: '. generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST'])); | ||
339 | + header('Location: ' . generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST'])); | ||
340 | exit; | ||
341 | } | ||
342 | } | ||
343 | - header('Location: ?'); exit; | ||
344 | + header('Location: '. $userspace . '?'); exit; | ||
345 | } else { | ||
346 | - $loginManager->handleFailedLogin($_SERVER); | ||
347 | + $errorReason = $loginManager->handleFailedLogin($_SERVER); | ||
348 | $redir = '&username='. urlencode($_POST['login']); | ||
349 | if (isset($_GET['post'])) { | ||
350 | $redir .= '&post=' . urlencode($_GET['post']); | ||
351 | @@ -270,7 +291,7 @@ function isLoggedIn() | ||
352 | } | ||
353 | } | ||
354 | // Redirect to login screen. | ||
355 | - echo '<script>alert("'. t("Wrong login/password.") .'");document.location=\'?do=login'.$redir.'\';</script>'; | ||
356 | + echo '<script>alert("'. t($errorReason) .'");document.location=\'?do=login'.$redir.'\';</script>'; | ||
357 | exit; | ||
358 | } | ||
359 | } | ||
360 | @@ -1719,7 +1740,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) | ||
361 | * @param SessionManager $sessionManager SessionManager instance | ||
362 | * @param LoginManager $loginManager LoginManager instance | ||
363 | */ | ||
364 | -function install($conf, $sessionManager, $loginManager) { | ||
365 | +function install($conf, $sessionManager, $loginManager, $userspace) { | ||
366 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. | ||
367 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); | ||
368 | |||
369 | @@ -1755,7 +1776,7 @@ function install($conf, $sessionManager, $loginManager) { | ||
370 | } | ||
371 | |||
372 | |||
373 | - if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) | ||
374 | + if (true) | ||
375 | { | ||
376 | $tz = 'UTC'; | ||
377 | if (!empty($_POST['continent']) && !empty($_POST['city']) | ||
378 | @@ -1764,15 +1785,15 @@ function install($conf, $sessionManager, $loginManager) { | ||
379 | $tz = $_POST['continent'].'/'.$_POST['city']; | ||
380 | } | ||
381 | $conf->set('general.timezone', $tz); | ||
382 | - $login = $_POST['setlogin']; | ||
383 | - $conf->set('credentials.login', $login); | ||
384 | + $conf->set('credentials.login', $userspace); | ||
385 | $salt = sha1(uniqid('', true) .'_'. mt_rand()); | ||
386 | $conf->set('credentials.salt', $salt); | ||
387 | - $conf->set('credentials.hash', sha1($_POST['setpassword'] . $login . $salt)); | ||
388 | + $hash = sha1(uniqid('', true) .'_'. mt_rand()); | ||
389 | + $conf->set('credentials.hash', $hash); | ||
390 | if (!empty($_POST['title'])) { | ||
391 | $conf->set('general.title', escape($_POST['title'])); | ||
392 | } else { | ||
393 | - $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER))); | ||
394 | + $conf->set('general.title', ucwords(str_replace("_", " ", $userspace))); | ||
395 | } | ||
396 | $conf->set('translation.language', escape($_POST['language'])); | ||
397 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); | ||
398 | @@ -1841,7 +1862,12 @@ function install($conf, $sessionManager, $loginManager) { | ||
399 | $app = new \Slim\App($container); | ||
400 | |||
401 | // REST API routes | ||
402 | -$app->group('/api/v1', function() { | ||
403 | +if (isset($userspace)) { | ||
404 | + $mountpoint = '/' . $userspace . '/api/v1'; | ||
405 | +} else { | ||
406 | + $mountpoint = '/api/v1'; | ||
407 | +} | ||
408 | +$app->group($mountpoint, function() { | ||
409 | $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo'); | ||
410 | $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks'); | ||
411 | $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink'); | ||
412 | @@ -1860,7 +1886,7 @@ function install($conf, $sessionManager, $loginManager) { | ||
413 | $response = $app->run(true); | ||
414 | // Hack to make Slim and Shaarli router work together: | ||
415 | // If a Slim route isn't found and NOT API call, we call renderPage(). | ||
416 | -if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) { | ||
417 | +if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], $mountpoint) === false) { | ||
418 | // We use UTF-8 for proper international characters handling. | ||
419 | header('Content-Type: text/html; charset=utf-8'); | ||
420 | renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager, $loginManager); | ||