Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve API client usability #1368

Merged
merged 70 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
8c81604
Support API tokens per user
qwerty287 Jun 12, 2022
5e1d798
Do not require Accept and Content-Type headers
qwerty287 Jun 12, 2022
b5ca08b
Fix 500 on user creation
qwerty287 Jun 12, 2022
40fee32
Recompile
qwerty287 Jun 26, 2022
7ec4a68
Merge remote-tracking branch 'origin/master' into api-tokens
qwerty287 Jun 26, 2022
0ac74e4
Fix some reviews
qwerty287 Jun 29, 2022
20bf192
Undo Content-Type and Accept change
qwerty287 Jun 29, 2022
b47d039
Merge branch 'master' into api-tokens
qwerty287 Jun 29, 2022
ae2f277
Fix phpstan
qwerty287 Jun 29, 2022
595dc9c
Fix phpstan
qwerty287 Jun 29, 2022
4e15114
Fix phpstan 3
qwerty287 Jun 29, 2022
534bd12
merge from master
ildyria Jul 16, 2022
10c385c
add support for disabling the token completely rather than letting it…
ildyria Jul 16, 2022
b0057c3
disable-enable FK
ildyria Jul 16, 2022
00633aa
add tests
ildyria Jul 16, 2022
2491549
remove unused variable
ildyria Jul 16, 2022
55555d5
Merge branch 'master' into api-tokens
qwerty287 Jul 17, 2022
12a6014
Translate and add strings
qwerty287 Jul 17, 2022
28a706e
Fix security issue during migration that gives admin perms to api_key
qwerty287 Jul 18, 2022
3c558f9
Fix locale
qwerty287 Jul 20, 2022
cc265d4
Sync frontend
qwerty287 Jul 20, 2022
c51d0ef
Merge remote-tracking branch 'origin/master' into api-tokens
qwerty287 Jul 26, 2022
c3b1c0a
Merge remote-tracking branch 'origin/master' into api-tokens
qwerty287 Aug 2, 2022
0319237
Suggestions
qwerty287 Aug 5, 2022
ad270aa
Apply suggestions from code review
qwerty287 Aug 5, 2022
0c06d82
Apply suggestions
qwerty287 Aug 5, 2022
8412834
Recompile frontend
qwerty287 Aug 5, 2022
e1db64e
Fix perms
qwerty287 Aug 5, 2022
ba67ad3
Fix lint
qwerty287 Aug 5, 2022
d1e5264
Improve check
qwerty287 Aug 5, 2022
3a2c02e
Simplify middleware
nagmat84 Aug 5, 2022
5376b31
Assert JSON
qwerty287 Aug 6, 2022
1a34f13
fix format
qwerty287 Aug 6, 2022
35c5af0
Apply fixes from PHP-CS-Fixer (#1444)
github-actions[bot] Aug 6, 2022
d8ccc6e
Hash tokens
qwerty287 Aug 6, 2022
b42fa6d
Sync frontend
qwerty287 Aug 6, 2022
91c2096
Tmp commit to find out why it's failing
qwerty287 Aug 6, 2022
fb41b63
Second try to find failure
qwerty287 Aug 6, 2022
7611838
I'm pretty stupid at all
qwerty287 Aug 6, 2022
5bf6e60
Fix db errors
qwerty287 Aug 6, 2022
c974d1a
Merge branch 'master' into api-tokens
qwerty287 Sep 4, 2022
b5d4345
Fix phpstan
qwerty287 Sep 4, 2022
36072ba
Fix phpstan 2
qwerty287 Sep 4, 2022
d80094a
Fix phpstan 3
qwerty287 Sep 4, 2022
3e10d93
Fix test
qwerty287 Sep 4, 2022
3f57646
merge master
ildyria Sep 8, 2022
b79293f
Add tests and fix issues as guest
qwerty287 Sep 8, 2022
2424663
sync frontend
qwerty287 Sep 8, 2022
018d96b
fix phpdoc
qwerty287 Sep 8, 2022
4ff6f18
Update locales and sync frontedn
qwerty287 Sep 9, 2022
ed3e2f8
Fix duplicated keys
qwerty287 Sep 9, 2022
1d3d535
Sync frontend
qwerty287 Sep 9, 2022
daf9238
Add getAuthenticatedUser test
qwerty287 Sep 9, 2022
871eb59
Don't send token with user, fix locales, synced frontend
nagmat84 Sep 9, 2022
6c19699
Make PHPStan happy about something toally unrelated
nagmat84 Sep 9, 2022
5cf7730
Sync frontend
qwerty287 Sep 10, 2022
d222def
fix sync
qwerty287 Sep 10, 2022
8e9cde1
Remove HasUserMiddleware
nagmat84 Sep 10, 2022
61c866d
Fix tests
qwerty287 Sep 10, 2022
c5d2ff6
Added custom guard to handle session or token
nagmat84 Sep 10, 2022
16ecce3
Avoid unintended login as admin
nagmat84 Sep 11, 2022
e0ee662
Keep token-based authentication stateless + Fix tests
nagmat84 Sep 11, 2022
d6b8c95
Added test for logout
nagmat84 Sep 11, 2022
26b4bd4
Don't drop table
qwerty287 Sep 15, 2022
039d72f
Recompile frontend
qwerty287 Sep 15, 2022
9cd9f7c
Revert "Recompile frontend"
qwerty287 Sep 15, 2022
eaa3a17
Only migrate if not exists
qwerty287 Sep 15, 2022
b8916b8
Merge remote-tracking branch 'origin/master' into api-tokens
qwerty287 Sep 15, 2022
fc3fd82
Sync frontend to master
qwerty287 Sep 15, 2022
35bac96
Undo change
qwerty287 Sep 15, 2022
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
44 changes: 44 additions & 0 deletions app/Http/Controllers/Administration/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,48 @@ public function getEmail(): array
'email' => $user->email,
];
}

/**
* Returns the currently authenticated user.
*
* @return User
*/
public function getAuthenticatedUser(): User
{
/** @var User */
return Auth::user();
}
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Reset the token of the currently authenticated user.
*
* @return User
*
* @throws \Exception
*/
public function resetToken(): User
{
/** @var User $user */
$user = Auth::user();
$token = strtr(base64_encode(random_bytes(16)), '+/', '-_');
$user->token = hash('SHA512', $token);
$user->save();

$user->token = $token;

return $user;
}

/**
* Disable the token of the currently authenticated user.
*
* @return void
*/
public function unsetToken(): void
{
/** @var User $user */
$user = Auth::user();
$user->token = null;
$user->save();
}
}
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'admin',
\App\Http\Middleware\HasUserCheck::class,
],
];

Expand Down
44 changes: 44 additions & 0 deletions app/Http/Middleware/HasUserCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace App\Http\Middleware;

use App\Contracts\InternalLycheeException;
use App\Exceptions\UnauthorizedException;
use App\Http\Middleware\Checks\IsInstalled;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class HasUserCheck
{
private IsInstalled $isInstalled;

public function __construct(IsInstalled $isInstalled)
{
$this->isInstalled = $isInstalled;
}

/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
*
* @return mixed
*
* @throws UnauthorizedException
* @throws InternalLycheeException
*/
public function handle(Request $request, Closure $next): mixed
{
if (!$this->isInstalled->assert()) {
return $next($request);
}

if (!Auth::hasUser()) {
throw new UnauthorizedException('Requires authentication');
}

return $next($request);
}
nagmat84 marked this conversation as resolved.
Show resolved Hide resolved
}
36 changes: 14 additions & 22 deletions app/Http/Middleware/VerifyCsrfToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace App\Http\Middleware;

use App\Models\Configs;
use App\Exceptions\Internal\QueryBuilderException;
use App\Models\User;
use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
use Illuminate\Http\Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Facades\Auth;

class VerifyCsrfToken extends Middleware
{
Expand All @@ -23,38 +25,28 @@ class VerifyCsrfToken extends Middleware

/**
* The goal of this function is to allow to bypass the CSRF token requirement
* if an Authorization value is provided in the header and matches the apiKey.
*
* FIXME: Do we want to hash this API key ? Might actually be a good idea...
* if an Authorization value is provided in the header and matches the
* token of a user.
*
* @param Request $request
* @param Closure $next
*
* @return mixed
*
* @throws TokenMismatchException
* @throws QueryBuilderException
*/
public function handle($request, Closure $next): mixed
{
if ($request->is('api/*')) {
/**
* default value is ''
* we force it in case of the migration has not been done.
*/
$apiKey = Configs::getValueAsString('api_key');

/*
* if apiKey is the empty string we directly return the parent handle.
*/
if ($apiKey === '') {
return parent::handle($request, $next);
}
$token = $request->header('Authorization');
if ($request->is('api/*') && is_string($token)) {
/** @var User|null $user */
$user = User::query()
->where('token', '=', hash('SHA512', $token))
->first();
if ($user instanceof User) {
Auth::loginUsingId($user->id);
nagmat84 marked this conversation as resolved.
Show resolved Hide resolved

/*
* We are currently checking for Authorization.
* Do we also want to check if there is a POST value with the apiKey ?
*/
if ($request->header('Authorization') === $apiKey) {
return $next($request);
}
}
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/ChineseSimplified.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => '设置 OpenStreetMap 图层提供者',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => '智能相册',
'SHARED_ALBUMS' => '已共享的相册',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/ChineseTraditional.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => '設置OpenStreetMap圖層提供者',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => '智能相簿',
'SHARED_ALBUMS' => '共享的相簿',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Czech.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public function get_locale(): array
'SAVE_RISK' => 'Uložit změny, rizika jsou mi známa!',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Chytrá alba',
'SHARED_ALBUMS' => 'Sdílená alba',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Dutch.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Slimme albums',
'SHARED_ALBUMS' => 'Shared albums',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/English.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Smart albums',
'SHARED_ALBUMS' => 'Shared albums',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/French.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Selectioner le fournisseur de données cartographiques',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Smart Albums',
'SHARED_ALBUMS' => 'Albums partagés',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/German.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Speichere Provider für OpenStreetMap Karten',
'FULL_SETTINGS' => 'Alle Einstellungen',
'UPDATE' => 'Update',
'RESET' => 'Zurücksetzen',
'DISABLE_TOKEN_TOOLTIP' => 'Deaktivieren',
'ENABLE_TOKEN' => 'API-Schlüssel aktivieren',
'DISABLED_TOKEN_STATUS_MSG' => 'Deaktiviert',
'TOKEN_BUTTON' => 'API-Schlüssel ...',
'TOKEN_NOT_AVAILABLE' => 'Sie haben diesen Schlüssel bereits angesehen.',

'SAVE_RISK' => 'Änderungen speichern, ich kenne das Risiko!',

Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Greek.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Έξυπνα λευκώματα',
'SHARED_ALBUMS' => 'Κοινόχρηστα λευκώματα',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Italian.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Album smart',
'SHARED_ALBUMS' => 'Album condivisi',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/NorwegianBokmal.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Lagre leverandør for OpenStreetMap fliser',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Automatiske album',
'SHARED_ALBUMS' => 'Delte album',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Polish.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Inteligentne albumy',
'SHARED_ALBUMS' => 'Udostępnione albumy',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Portuguese.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Escolher OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Smart álbums',
'SHARED_ALBUMS' => 'Álbums partilhados',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Russian.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Метаальбомы',
'SHARED_ALBUMS' => 'Общие альбомы',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Slovak.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public function get_locale(): array
'SAVE_RISK' => 'Zmeny uložiť, riziko je známe!',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Inteligentné albumy',
'SHARED_ALBUMS' => 'Zdieľané albumy',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Spanish.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Álbumes inteligentes',
'SHARED_ALBUMS' => 'Álbumes compartidos',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Swedish.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Set OpenStreetMap tiles provider',
'FULL_SETTINGS' => 'Full Settings',
'UPDATE' => 'Update',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Smarta album',
'SHARED_ALBUMS' => 'Shared albums',
Expand Down
6 changes: 6 additions & 0 deletions app/Locale/Vietnamese.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public function get_locale(): array
'SET_MAP_PROVIDER' => 'Cài đặt nhà cung cấp ô bản đồ OpenStreetMap',
'FULL_SETTINGS' => 'Toàn bộ cài đặt',
'UPDATE' => 'Cập nhật',
'RESET' => 'Reset',
'DISABLE_TOKEN_TOOLTIP' => 'Disable',
'ENABLE_TOKEN' => 'Enable API token',
'DISABLED_TOKEN_STATUS_MSG' => 'disabled',
'TOKEN_BUTTON' => 'API token ...',
'TOKEN_NOT_AVAILABLE' => 'You already viewed this token.',

'SMART_ALBUMS' => 'Những album thông minh',
'SHARED_ALBUMS' => 'Những album được chia sẻ',
Expand Down
Loading