mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Fix FLEXIAPI-258 Move DotEnv instance configurations in the Spaces table
This commit is contained in:
parent
b66cc28004
commit
9006bc1d0d
52 changed files with 685 additions and 201 deletions
|
|
@ -19,6 +19,7 @@ v1.7
|
|||
- Fix FLEXIAPI-256 Publish an empty string while deleting a device on Redis to force the refresh on the other clients
|
||||
- Fix FLEXIAPI-268 Allow pn-param in Apple format for the push notifications endpoints
|
||||
- Fix FLEXIAPI-269 Update the IsNotPhoneNumber rule to use a better phone number validator
|
||||
- Fix FLEXIAPI-258 Move DotEnv instance configurations in the Spaces table
|
||||
|
||||
v1.6
|
||||
----
|
||||
|
|
|
|||
43
INSTALL.md
43
INSTALL.md
|
|
@ -4,7 +4,9 @@ FlexiAPI relies on [DotEnv](https://github.com/vlucas/phpdotenv) to be configure
|
|||
|
||||
Thoses variables can then be set using Docker-Compose, a bash script or a web-server.
|
||||
|
||||
If you're installing FlexiAPI from the RPM package you can find the configuration file at `/etc/flexisip-account-manager/flexiapi.env`.
|
||||
If you're installing FlexiAPI from the RedHat or Debian package you can find the configuration file at `/etc/flexisip-account-manager/flexiapi.env`.
|
||||
|
||||
Check also the [RELEASE.md](RELEASE.md) to check if you don't have specific migrations to do between releases.
|
||||
|
||||
# 1.a Manual setup
|
||||
|
||||
|
|
@ -13,14 +15,6 @@ Clone the repository, install the dependencies and generate a key.
|
|||
composer install --no-dev
|
||||
php artisan key:generate
|
||||
|
||||
Then configure the database connection in the `.env` file (from the `.env.example` one). And migrate the tables. The first migration *MUST* be run on an empty database.
|
||||
|
||||
php artisan migrate
|
||||
|
||||
You can also run the test suit using `phpunit`.
|
||||
|
||||
To know more about the web server configuration part, you can directly [visit the official Laravel installation documentation](https://laravel.com/docs/).
|
||||
|
||||
# 1.b Packages setup
|
||||
|
||||
FlexiAPI is packaged for Debian and RedHat, you can setup those repositories using the Flexisip documentation https://wiki.linphone.org/xwiki/wiki/public/view/Flexisip/1.%20Installation/#HInstallationfromourrepositories
|
||||
|
|
@ -28,14 +22,18 @@ FlexiAPI is packaged for Debian and RedHat, you can setup those repositories usi
|
|||
yum install bc-flexisip-account-manager # For RedHat distributions
|
||||
apt install bc-flexisip-account-manager # For Debian distributions
|
||||
|
||||
The `artisan` script is in the root directory of where the application is setup, with packages its often `/opt/belledonne-communications/share/flexisip-account-manager/flexiapi/`.
|
||||
|
||||
# 2. Web server configuration
|
||||
|
||||
The package will deploy a `flexisip-account-manager.conf` file in the apache2 configuration directory.
|
||||
This file can be loaded and configured in your specific VirtualHost configuration.
|
||||
|
||||
To know more about the web server configuration part, you can directly [visit the official Laravel installation documentation](https://laravel.com/docs/).
|
||||
|
||||
# 3. .env file configuration
|
||||
|
||||
Complete all the other variables in the `.env` file or by overwritting them in your Docker or web-server configuration.
|
||||
Complete all the variables in the `.env` file (from the `.env.example` one if you setup the instance manually) or by overwritting them in your Docker or web-server configuration.
|
||||
|
||||
## 3.1. Mandatory `APP_ROOT_HOST` variable
|
||||
|
||||
|
|
@ -48,9 +46,11 @@ This is the host that you'll define in the Apache or webserver VirtualHost:
|
|||
|
||||
If you are planning to manage several SIP domains (see Spaces bellow) a wildcard `ServerAlias` as above is required.
|
||||
|
||||
## 3.2. For manual setups
|
||||
## 3.2. Database migration
|
||||
|
||||
`APP_KEY` Can be set using the `php artisan key:generate` command.
|
||||
Then configure the database connection parameters and migrate the tables. The first migration *MUST* be run on an empty database.
|
||||
|
||||
php artisan migrate
|
||||
|
||||
# 4. Spaces
|
||||
|
||||
|
|
@ -106,24 +106,9 @@ On nginx use `fastcgi_param` to pass the parameter directly to PHP.
|
|||
> **Warning** Do not create a cache of your configuration (using `artisan config:cache`) if you have a multi-environnement setup.
|
||||
> The cache is always having the priority on the variables set in the configuration files.
|
||||
|
||||
## Multiple .env option
|
||||
|
||||
To do so, configure several web servers virtualhosts and set a specific `APP_ENV` environnement variable in each of them.
|
||||
|
||||
Note that if `APP_ENV` is not set FlexiAPI will directly use the default `.env` file.
|
||||
|
||||
FlexiAPI will then try to load a custom configuration file with the following name `.env.$APP_ENV`. So for the previous example `.env.foobar`.
|
||||
|
||||
You can then configure your instances with specific values.
|
||||
|
||||
INSTANCE_COPYRIGHT="FooBar - Since 1997"
|
||||
INSTANCE_INTRO_REGISTRATION="Welcome on the FooBar Server"
|
||||
INSTANCE_CUSTOM_THEME=true
|
||||
…
|
||||
|
||||
## Custom theme
|
||||
|
||||
If you set `INSTANCE_CUSTOM_THEME` to true, FlexiAPI will try to load a CSS file located in `public/css/$APP_ENV.style.css`. If the file doesn't exists it will fallback to `public/css/style.css`.
|
||||
If you enable the Custom CSS Theme option to true in the Space administration panel, FlexiAPI will try to load a CSS file located in `public/css/$space_host.style.css`. If the file doesn't exists it will fallback to `public/css/style.css`.
|
||||
|
||||
You can find an example CSS file at `public/css/custom.style.css`.
|
||||
|
||||
|
|
@ -140,7 +125,7 @@ This binary will be executed under "web user" privileges. Ensure that all the re
|
|||
|
||||
## SELinux restrictions
|
||||
|
||||
If you are running on a CentOS/RedHat machine, please ensure that SELinux is correctly configured.
|
||||
If you are running on a RedHat machine, please ensure that SELinux is correctly configured.
|
||||
|
||||
Allow the webserver user to write in the `storage/` directory:
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Once deployed you can have access to the global and API documentation on the `/a
|
|||
|
||||
# Setup
|
||||
|
||||
Check the `INSTALL.md` file.
|
||||
Check the [INSTALL.md](INSTALL.md) and [CHANGELOG.md](CHANGELOG.md) files.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -39,6 +39,12 @@ Create or update a Space, required to then create accounts afterward. The `super
|
|||
|
||||
php artisan spaces:create-update {sip_domain} {host} {--super}
|
||||
|
||||
### Import the old DotEnv instance configuration into a Space
|
||||
|
||||
Since 1.7 some environnement instance configuration variables were moved into the Space configuration, you can import them using this command.
|
||||
|
||||
php artisan spaces:import-configuration-from-dot-env {sip_domain}
|
||||
|
||||
### Create an admin account
|
||||
|
||||
Create an admin account, an API Key will also be generated along the way, it might expire after a while (regarding the API Key expiration policy). An empty `api_key_ip` will remove the IP restriction on the key.
|
||||
|
|
|
|||
53
RELEASE.md
53
RELEASE.md
|
|
@ -13,32 +13,66 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|||
- **New mandatory DotEnv variable** `APP_ROOT_HOST`, replaces `APP_URL` and `APP_SIP_DOMAIN` that are now configured using the new dedicated Artisan script. It defines the root hostname where all the Spaces will be configured. All the Spaces will be as subdomains of `APP_ROOT_HOST` except one that can be equal to `APP_ROOT_HOST`. Example: if `APP_ROOT_HOST=myhost.com` the Spaces hosts will be `myhost.com`, `alpha.myhost.com` , `beta.myhost.com`...
|
||||
- **New Artisan script** `php artisan spaces:create-update {sip_domain} {host} {--super}`, replaces `php artisan sip_domains:create-update {sip_domain} {--super}`. Can create a Space or update a Space Host base on its Space SIP Domain.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Removing and moving DotEnv instance environnement variables to the Spaces** The following DotEnv variables were removed. You can now configure them directly in the designated spaces.
|
||||
- INSTANCE_COPYRIGHT
|
||||
- INSTANCE_INTRO_REGISTRATION
|
||||
- INSTANCE_CUSTOM_THEME
|
||||
- INSTANCE_CONFIRMED_REGISTRATION_TEXT
|
||||
- WEB_PANEL
|
||||
- PUBLIC_REGISTRATION
|
||||
- PHONE_AUTHENTICATION
|
||||
- DEVICES_MANAGEMENT
|
||||
- INTERCOM_FEATURES
|
||||
- NEWSLETTER_REGISTRATION_ADDRESS
|
||||
- ACCOUNT_PROXY_REGISTRAR_ADDRESS
|
||||
- ACCOUNT_TRANSPORT_PROTOCOL_TEXT
|
||||
- ACCOUNT_REALM
|
||||
- ACCOUNT_PROVISIONING_RC_FILE
|
||||
- ACCOUNT_PROVISIONING_OVERWRITE_ALL
|
||||
- ACCOUNT_PROVISIONING_USE_X_LINPHONE_PROVISIONING_HEADER
|
||||
|
||||
#### Migrate from [1.6]
|
||||
|
||||
1. Deploy the new version and migrate the database.
|
||||
|
||||
```
|
||||
php artisan migrate
|
||||
php artisan migrate
|
||||
```
|
||||
|
||||
2. Set `APP_ROOT_HOST` in `.env` or as an environnement variable. And remove `APP_URL` and `APP_SIP_DOMAIN`
|
||||
|
||||
```
|
||||
APP_ROOT_HOST=myhost.com
|
||||
APP_ROOT_HOST=myhost.com
|
||||
```
|
||||
|
||||
3. The migration script will automatically copy the `sip_domain` into `host` in the `spaces` table. You then have to "fix" the hosts and set them to equal or be subdomains of `APP_ROOT_HOST`.
|
||||
|
||||
```
|
||||
php artisan spaces:create-update my.sip myhost.com --super # You can set some Spaces as SuperSpaces, the admin will be able to manage the other spaces
|
||||
php artisan spaces:create-update alpha.sip alpha.myhost.com
|
||||
php artisan spaces:create-update beta.sip beta.myhost.com
|
||||
...
|
||||
php artisan spaces:create-update my.sip myhost.com --super # You can set some Spaces as SuperSpaces, the admin will be able to manage the other spaces
|
||||
php artisan spaces:create-update alpha.sip alpha.myhost.com
|
||||
php artisan spaces:create-update beta.sip beta.myhost.com
|
||||
...
|
||||
```
|
||||
|
||||
4. Configure your web server to point the `APP_ROOT_HOST` and subdomains to the app.
|
||||
|
||||
5. Configure the upcoming Spaces
|
||||
5. Configure the upcoming Spaces.
|
||||
|
||||
6. Remove the instance based environnement variables and configure them directly in the spaces.
|
||||
|
||||
7. (Optional) Import the old instance DotEnv environnement variables into a space.
|
||||
|
||||
```
|
||||
php artisan spaces:import-configuration-from-dot-env {sip_domain}
|
||||
```
|
||||
|
||||
You can find more details regarding those steps in the [`INSTALL.md`](INSTALL.md) file.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- **Last major version supporting the deprecated endpoints of the API**
|
||||
|
||||
## [1.5] - 2024-08-29
|
||||
|
||||
|
|
@ -63,8 +97,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|||
- **New DotEnv variable:** HCAPTCHA_SECRET=secret-key
|
||||
- **New DotEnv variable:** HCAPTCHA_SITEKEY=site-key
|
||||
- **Localization support:** The API is now accepting the `Accept-Language` header and adapt its internal localization to the client/browser one. For the moment only French and English are supported but more languages could be added in the future.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- **Last major version supporting the deprecated endpoints of the API**
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,6 @@ APP_FLEXISIP_PUSHER_FIREBASE_KEYSMAP= # Each pair is separated using a space and
|
|||
|
||||
APP_ALLOW_PHONE_NUMBER_USERNAME_ADMIN_API=false # Allow phone numbers to be set as username in admin account creation endpoints
|
||||
|
||||
# Instance specific parameters
|
||||
INSTANCE_COPYRIGHT= # Simple text displayed in the page footer
|
||||
INSTANCE_INTRO_REGISTRATION= # Markdown text displayed in the home page
|
||||
INSTANCE_CUSTOM_THEME=false
|
||||
INSTANCE_CONFIRMED_REGISTRATION_TEXT= # Markdown text displayed when an account is confirmed
|
||||
|
||||
WEB_PANEL=true # Fully enable/disable the web panels
|
||||
PUBLIC_REGISTRATION=true # Toggle to enable/disable the public registration forms
|
||||
PHONE_AUTHENTICATION=true # Toggle to enable/disable the SMS support, requires public registration
|
||||
DEVICES_MANAGEMENT=false # Toggle to enable/disable the devices management supporttrue
|
||||
INTERCOM_FEATURES=false # Toggle to enable/disable the intercom related features
|
||||
|
||||
NEWSLETTER_REGISTRATION_ADDRESS= # Address to contact when a user wants to register to the newsletter
|
||||
TERMS_OF_USE_URL= # A URL pointing to the Terms of Use
|
||||
PRIVACY_POLICY_URL= # A URL pointing to the Privacy Policy
|
||||
APP_PROJECT_URL= # A URL pointing to the project information page
|
||||
|
|
@ -32,11 +19,6 @@ LOG_CHANNEL=stack
|
|||
# Risky toggles
|
||||
APP_DANGEROUS_ENDPOINTS=false # Enable some dangerous endpoints used for XMLRPC like fallback usage
|
||||
|
||||
# SIP server parameters
|
||||
ACCOUNT_PROXY_REGISTRAR_ADDRESS=sip.example.com # Proxy registrar address, can be different than the SIP domain
|
||||
ACCOUNT_TRANSPORT_PROTOCOL_TEXT="TLS (recommended), TCP or UDP" # Simple text, to explain how the SIP server can be reached
|
||||
ACCOUNT_REALM=null # Default realm for the accounts, fallback to the domain if not set, enforce null by default
|
||||
|
||||
# Expiration time for tokens and code, in minutes, 0 means no expiration
|
||||
APP_API_ACCOUNT_CREATION_TOKEN_RETRY_MINUTES=60 # Number of minutes between two consecutive account_creation_token creation
|
||||
APP_ACCOUNT_CREATION_TOKEN_EXPIRATION_MINUTES=0
|
||||
|
|
@ -54,11 +36,6 @@ ACCOUNT_USERNAME_REGEX="^[a-z0-9+_.-]*$"
|
|||
ACCOUNT_DEFAULT_PASSWORD_ALGORITHM=SHA-256 # Can ONLY be MD5 or SHA-256 in capital, default to SHA-256
|
||||
ACCOUNT_AUTHENTICATION_BEARER= # Bearer value (WWW-Authenticate: Bearer <value>) of the external service that can provide a trusted (eg. JWT token) for the authentication, takes priority and disable the DIGEST auth if set, see https://www.rfc-editor.org/rfc/rfc8898
|
||||
|
||||
# Account provisioning
|
||||
ACCOUNT_PROVISIONING_RC_FILE=
|
||||
ACCOUNT_PROVISIONING_OVERWRITE_ALL=
|
||||
ACCOUNT_PROVISIONING_USE_X_LINPHONE_PROVISIONING_HEADER=true
|
||||
|
||||
# Blocking service
|
||||
BLOCKING_TIME_PERIOD_CHECK=30 # Time span on which the blocking service will proceed, in minutes
|
||||
BLOCKING_AMOUNT_EVENTS_AUTHORIZED_DURING_PERIOD=5 # Amount of account events authorized during this period
|
||||
|
|
|
|||
|
|
@ -307,12 +307,12 @@ class Account extends Authenticatable
|
|||
|
||||
public function getRealmAttribute()
|
||||
{
|
||||
return config('app.account_realm');
|
||||
return space()?->account_realm;
|
||||
}
|
||||
|
||||
public function getResolvedRealmAttribute()
|
||||
{
|
||||
return config('app.account_realm') ?? $this->domain;
|
||||
return space()?->account_realm ?? $this->domain;
|
||||
}
|
||||
|
||||
public function getConfirmationKeyExpiresAttribute()
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class CreateAdminAccount extends Command
|
|||
{
|
||||
$spaces = Space::all('domain')->pluck('domain');
|
||||
|
||||
$this->info('Your will create a new admin account in the database, existing accounts with the same credentials will be overwritten');
|
||||
$this->info('Your creating a new admin account in the database, existing accounts with the same credentials will be overwritten');
|
||||
|
||||
$username = $this->option('username');
|
||||
$domain = $this->option('domain');
|
||||
|
|
|
|||
|
|
@ -29,12 +29,16 @@ class CreateUpdate extends Command
|
|||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Your will create or update a Space in the database');
|
||||
$this->info('Your are creating or updating a Space in the database');
|
||||
|
||||
if (empty(config('app.root_host'))) {
|
||||
$this->error('The environnement variable APP_ROOT_HOST doesn\'t seems to be set');
|
||||
}
|
||||
|
||||
if (!str_ends_with($this->argument('host'), config('app.root_host'))) {
|
||||
$this->error('The provided host doesn\'t seems to ends with ' . config('app.root_host'));
|
||||
}
|
||||
|
||||
$space = Space::where('domain', $this->argument('sip_domain'))->firstOrNew();
|
||||
$space->host = $this->argument('host');
|
||||
$space->domain = $this->argument('sip_domain');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Spaces;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Space;
|
||||
|
||||
class ImportConfigurationFromDotEnv extends Command
|
||||
{
|
||||
protected $signature = 'spaces:import-configuration-from-dot-env {sip_domain}';
|
||||
protected $description = 'Import the deprecated space DotEnv configuration in a Space';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$space = Space::where('domain', $this->argument('sip_domain'))->first();
|
||||
|
||||
if (!$space) {
|
||||
$this->error('The space cannot be found');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('The following configuration will be imported in the space ' . $space->domain);
|
||||
$this->info('The existing settings will be overwritten:');
|
||||
|
||||
$space->custom_theme = env('INSTANCE_CUSTOM_THEME', false);
|
||||
$space->web_panel = env('WEB_PANEL', true);
|
||||
|
||||
$space->copyright_text = env('INSTANCE_COPYRIGHT', null);
|
||||
$space->intro_registration_text = env('INSTANCE_INTRO_REGISTRATION', null);
|
||||
$space->confirmed_registration_text = env('INSTANCE_CONFIRMED_REGISTRATION_TEXT', null);
|
||||
$space->newsletter_registration_address = env('NEWSLETTER_REGISTRATION_ADDRESS', null);
|
||||
$space->account_proxy_registrar_address = env('ACCOUNT_PROXY_REGISTRAR_ADDRESS', 'sip.domain.com');
|
||||
$space->account_realm = env('ACCOUNT_REALM', null);
|
||||
$space->custom_provisioning_overwrite_all = env('ACCOUNT_PROVISIONING_OVERWRITE_ALL', false);
|
||||
$space->provisioning_use_linphone_provisioning_header = env('ACCOUNT_PROVISIONING_USE_X_LINPHONE_PROVISIONING_HEADER', true);
|
||||
|
||||
$space->public_registration = env('PUBLIC_REGISTRATION', true);
|
||||
$space->phone_registration = env('PHONE_AUTHENTICATION', true);
|
||||
$space->intercom_features = env('INTERCOM_FEATURES', false);
|
||||
|
||||
foreach ($space->getDirty() as $key => $value) {
|
||||
$show = ' - ' . $key . ' => ';
|
||||
$show .= ($value == null) ? 'null' : $value;
|
||||
|
||||
$this->info($show);
|
||||
}
|
||||
|
||||
if ($this->confirm('Do you want to update ' . $space->domain . '?', false)) {
|
||||
$space->save();
|
||||
$this->info('Space updated');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
use Illuminate\Support\Str;
|
||||
|
||||
use App\Account;
|
||||
use App\Space;
|
||||
use App\DigestNonce;
|
||||
use Illuminate\Http\Request;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
|
@ -27,6 +28,20 @@ use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
|
|||
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$hostSpace = null;
|
||||
|
||||
function space($reload = false): ?Space
|
||||
{
|
||||
global $hostSpace;
|
||||
|
||||
if ($hostSpace != null && $reload == false) {
|
||||
return $hostSpace;
|
||||
}
|
||||
|
||||
$hostSpace = Space::where('host', request()->host())->first();
|
||||
return $hostSpace;
|
||||
}
|
||||
|
||||
function passwordAlgorithms(): array
|
||||
{
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class ProvisioningController extends Controller
|
|||
private function checkProvisioningHeader(Request $request)
|
||||
{
|
||||
if (!$request->hasHeader('x-linphone-provisioning')
|
||||
&& config('app.provisioning_use_x_linphone_provisioning_header')) {
|
||||
&& space()?->provisioning_use_linphone_provisioning_header) {
|
||||
abort(400, 'x-linphone-provisioning header is missing');
|
||||
}
|
||||
}
|
||||
|
|
@ -169,11 +169,8 @@ class ProvisioningController extends Controller
|
|||
|
||||
$dom->appendChild($config);
|
||||
|
||||
// Default RC file handling
|
||||
$rcFile = config('app.provisioning_rc_file');
|
||||
|
||||
if (file_exists($rcFile)) {
|
||||
$rc = parse_ini_file($rcFile, true);
|
||||
if (space()?->custom_provisioning_entries) {
|
||||
$rc = parse_ini_string(space()->custom_provisioning_entries, true);
|
||||
|
||||
foreach ($rc as $sectionName => $values) {
|
||||
$section = $dom->createElement('section');
|
||||
|
|
@ -356,7 +353,7 @@ class ProvisioningController extends Controller
|
|||
}
|
||||
|
||||
// Overwrite all the entries
|
||||
if (config('app.provisioning_overwrite_all')) {
|
||||
if (space()?->custom_provisioning_overwrite_all) {
|
||||
$xpath = new \DOMXpath($dom);
|
||||
$entries = $xpath->query("//section/entry");
|
||||
if (!is_null($entries)) {
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class AccountImportController extends Controller
|
|||
'account_id' => $passwordAccount->id,
|
||||
'password' => bchash(
|
||||
$passwordAccount->username,
|
||||
config('app.account_realm') ?? $request->get('domain'),
|
||||
space()?->account_realm ?? $request->get('domain'),
|
||||
$passwords[$passwordAccount->username],
|
||||
$algorithm
|
||||
),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use Illuminate\Http\Request;
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Space;
|
||||
use App\Rules\Ini;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SpaceController extends Controller
|
||||
|
|
@ -87,20 +88,35 @@ class SpaceController extends Controller
|
|||
'max_account' => 'required|integer',
|
||||
]);
|
||||
|
||||
$space = $this->setConfig($request, $space);
|
||||
$space = $this->setAppConfiguration($request, $space);
|
||||
$space->save();
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function parameters(Space $space)
|
||||
public function configuration(Space $space)
|
||||
{
|
||||
return view('admin.space.parameters', [
|
||||
return view('admin.space.configuration', [
|
||||
'space' => $space
|
||||
]);
|
||||
}
|
||||
|
||||
public function parametersUpdate(Request $request, Space $space)
|
||||
public function configurationUpdate(Request $request, Space $space)
|
||||
{
|
||||
$space = $this->setConfiguration($request, $space);
|
||||
$space->save();
|
||||
|
||||
return redirect()->route('admin.spaces.configuration', $space);
|
||||
}
|
||||
|
||||
public function administration(Space $space)
|
||||
{
|
||||
return view('admin.space.administration', [
|
||||
'space' => $space
|
||||
]);
|
||||
}
|
||||
|
||||
public function administrationUpdate(Request $request, Space $space)
|
||||
{
|
||||
$request->validate([
|
||||
'max_accounts' => 'required|integer|min:0',
|
||||
|
|
@ -116,12 +132,38 @@ class SpaceController extends Controller
|
|||
$space->super = getRequestBoolean($request, 'super');
|
||||
$space->max_accounts = $request->get('max_accounts');
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
$space->custom_theme = getRequestBoolean($request, 'custom_theme');
|
||||
$space->web_panel = getRequestBoolean($request, 'web_panel');
|
||||
$space->save();
|
||||
|
||||
return redirect()->route('admin.spaces.show', $space);
|
||||
}
|
||||
|
||||
private function setConfig(Request $request, Space $space)
|
||||
private function setConfiguration(Request $request, Space $space)
|
||||
{
|
||||
$request->validate([
|
||||
'newsletter_registration_address' => 'nullable|email',
|
||||
'custom_provisioning_entries' => ['nullable', new Ini]
|
||||
]);
|
||||
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->confirmed_registration_text = $request->get('confirmed_registration_text');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||
$space->account_realm = $request->get('account_realm');
|
||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||
$space->custom_provisioning_overwrite_all = getRequestBoolean($request, 'custom_provisioning_overwrite_all');
|
||||
$space->provisioning_use_linphone_provisioning_header = getRequestBoolean($request, 'provisioning_use_linphone_provisioning_header');
|
||||
|
||||
$space->public_registration = getRequestBoolean($request, 'public_registration');
|
||||
$space->phone_registration = getRequestBoolean($request, 'phone_registration');
|
||||
$space->intercom_features = getRequestBoolean($request, 'intercom_features');
|
||||
|
||||
return $space;
|
||||
}
|
||||
|
||||
private function setAppConfiguration(Request $request, Space $space)
|
||||
{
|
||||
$request->validate([
|
||||
'max_account' => 'required|integer',
|
||||
|
|
|
|||
|
|
@ -59,6 +59,21 @@ class SpaceController extends Controller
|
|||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->confirmed_registration_text = $request->get('confirmed_registration_text');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||
$space->account_realm = $request->get('account_realm');
|
||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||
$this->setRequestBoolean($request, $space, 'custom_provisioning_overwrite_all');
|
||||
$this->setRequestBoolean($request, $space, 'provisioning_use_linphone_provisioning_header');
|
||||
$this->setRequestBoolean($request, $space, 'custom_theme');
|
||||
$this->setRequestBoolean($request, $space, 'web_panel');
|
||||
$this->setRequestBoolean($request, $space, 'public_registration');
|
||||
$this->setRequestBoolean($request, $space, 'phone_registration');
|
||||
$this->setRequestBoolean($request, $space, 'intercom_features');
|
||||
|
||||
$space->save();
|
||||
|
||||
return $space->refresh();
|
||||
|
|
@ -86,6 +101,14 @@ class SpaceController extends Controller
|
|||
'max_account' => 'required|integer',
|
||||
'max_accounts' => 'required|integer',
|
||||
'expire_at' => 'nullable|date|after_or_equal:today',
|
||||
|
||||
'custom_provisioning_overwrite_all' => 'required|boolean',
|
||||
'provisioning_use_linphone_provisioning_header' => 'required|boolean',
|
||||
'custom_theme' => 'required|boolean',
|
||||
'web_panel' => 'required|boolean',
|
||||
'public_registration' => 'required|boolean',
|
||||
'phone_registration' => 'required|boolean',
|
||||
'intercom_features' => 'required|boolean',
|
||||
]);
|
||||
|
||||
$space = Space::where('domain', $domain)->firstOrFail();
|
||||
|
|
@ -115,6 +138,22 @@ class SpaceController extends Controller
|
|||
$space->max_account = $request->get('max_account', 0);
|
||||
$space->max_accounts = $request->get('max_accounts', 0);
|
||||
$space->expire_at = $request->get('expire_at');
|
||||
|
||||
$space->copyright_text = $request->get('copyright_text');
|
||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||
$space->confirmed_registration_text = $request->get('confirmed_registration_text');
|
||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||
$space->account_realm = $request->get('account_realm');
|
||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||
$space->custom_provisioning_overwrite_all = $request->get('custom_provisioning_overwrite_all');
|
||||
$space->provisioning_use_linphone_provisioning_header = $request->get('provisioning_use_linphone_provisioning_header');
|
||||
$space->custom_theme = $request->get('custom_theme');
|
||||
$space->web_panel = $request->get('web_panel');
|
||||
$space->public_registration = $request->get('public_registration');
|
||||
$space->phone_registration = $request->get('phone_registration');
|
||||
$space->intercom_features = $request->get('intercom_features');
|
||||
|
||||
$space->save();
|
||||
|
||||
return $space;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ class Kernel extends HttpKernel
|
|||
'auth.check_blocked' => \App\Http\Middleware\CheckBlocked::class,
|
||||
'validate_json' => \App\Http\Middleware\ValidateJSON::class,
|
||||
'web_panel_enabled' => \App\Http\Middleware\IsWebPanelEnabled::class,
|
||||
'public_registration' => \App\Http\Middleware\IsPublicRegistration::class,
|
||||
'phone_registration' => \App\Http\Middleware\IsPhoneRegistration::class,
|
||||
'intercom_features' => \App\Http\Middleware\IsIntercomFeatures::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class AuthenticateDigestOrKey
|
|||
->where('domain', $domain)
|
||||
->firstOrFail();
|
||||
|
||||
$resolvedRealm = config('app.account_realm') ?? $domain;
|
||||
$resolvedRealm = space()?->account_realm ?? $domain;
|
||||
|
||||
// DIGEST authentication
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ class AuthenticateDigestOrKey
|
|||
private function generateAuthHeaders(Account $account, string $nonce): array
|
||||
{
|
||||
$headers = [];
|
||||
$resolvedRealm = config('app.account_realm') ?? $account->domain;
|
||||
$resolvedRealm = space()?->account_realm ?? $account->domain;
|
||||
|
||||
foreach ($account->passwords as $password) {
|
||||
if ($password->algorithm == 'CLRTXT') {
|
||||
|
|
|
|||
19
flexiapi/app/Http/Middleware/IsIntercomFeatures.php
Normal file
19
flexiapi/app/Http/Middleware/IsIntercomFeatures.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsIntercomFeatures
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->intercom_features) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Intercom features disabled');
|
||||
}
|
||||
}
|
||||
36
flexiapi/app/Http/Middleware/IsPhoneRegistration.php
Normal file
36
flexiapi/app/Http/Middleware/IsPhoneRegistration.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsPhoneRegistration
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->phone_registration) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Phone registration disabled');
|
||||
}
|
||||
}
|
||||
36
flexiapi/app/Http/Middleware/IsPublicRegistration.php
Normal file
36
flexiapi/app/Http/Middleware/IsPublicRegistration.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsPublicRegistration
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (space()?->public_registration) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Public registration disabled');
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ class IsSpaceExpired
|
|||
return abort(503, 'APP_ROOT_HOST is not configured');
|
||||
}
|
||||
|
||||
$space = \App\Space::where('host', $request->header('host'))->first();
|
||||
$space = space();
|
||||
|
||||
if ($space) {
|
||||
if (!str_ends_with($space->host, config('app.root_host'))) {
|
||||
|
|
|
|||
|
|
@ -21,19 +21,13 @@ namespace App\Http\Middleware;
|
|||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Space;
|
||||
|
||||
class IsWebPanelEnabled
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$request->expectsJson() && config('app.web_panel')) {
|
||||
if (!$request->expectsJson() && space()?->web_panel) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
|
|
|||
35
flexiapi/app/Rules/Ini.php
Normal file
35
flexiapi/app/Rules/Ini.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2022 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
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
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class Ini implements Rule
|
||||
{
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
return parse_ini_string($value) != false;
|
||||
}
|
||||
|
||||
public function message()
|
||||
{
|
||||
return 'Invalid ini format';
|
||||
}
|
||||
}
|
||||
|
|
@ -123,8 +123,8 @@ class AccountService
|
|||
);
|
||||
|
||||
if (!$request->api) {
|
||||
if (!empty(config('app.newsletter_registration_address')) && $request->has('newsletter')) {
|
||||
Mail::to(config('app.newsletter_registration_address'))->send(new NewsletterRegistration($account));
|
||||
if (!empty(space()?->newsletter_registration_address) && $request->has('newsletter')) {
|
||||
Mail::to(space()->newsletter_registration_address)->send(new NewsletterRegistration($account));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,16 +20,6 @@ return [
|
|||
'terms_of_use_url' => env('TERMS_OF_USE_URL', ''),
|
||||
'privacy_policy_url' => env('PRIVACY_POLICY_URL', ''),
|
||||
|
||||
'newsletter_registration_address' => env('NEWSLETTER_REGISTRATION_ADDRESS', ''),
|
||||
'phone_authentication' => env('PHONE_AUTHENTICATION', true),
|
||||
'public_registration' => env('PUBLIC_REGISTRATION', true),
|
||||
'intercom_features' => env('INTERCOM_FEATURES', false),
|
||||
'devices_management' => env('DEVICES_MANAGEMENT', false),
|
||||
'web_panel' => env('WEB_PANEL', true),
|
||||
|
||||
'proxy_registrar_address' => env('ACCOUNT_PROXY_REGISTRAR_ADDRESS', 'sip.domain.com'),
|
||||
'transport_protocol_text' => env('ACCOUNT_TRANSPORT_PROTOCOL_TEXT', 'TLS (recommended), TCP or UDP'),
|
||||
|
||||
'allow_phone_number_username_admin_api' => env('APP_ALLOW_PHONE_NUMBER_USERNAME_ADMIN_API', false),
|
||||
'account_blacklisted_usernames' => env('ACCOUNT_BLACKLISTED_USERNAMES', ''),
|
||||
'account_email_unique' => env('ACCOUNT_EMAIL_UNIQUE', false),
|
||||
|
|
@ -37,12 +27,6 @@ return [
|
|||
'account_default_password_algorithm' => env('ACCOUNT_DEFAULT_PASSWORD_ALGORITHM', 'SHA-256'),
|
||||
'account_authentication_bearer' => env('ACCOUNT_AUTHENTICATION_BEARER', null),
|
||||
|
||||
/**
|
||||
* Set a global realm for all the accounts, if not set, the account domain
|
||||
* will be used as a fallback
|
||||
*/
|
||||
'account_realm' => env('ACCOUNT_REALM', null),
|
||||
|
||||
/**
|
||||
* Time limit before the API Key and related cookie are expired
|
||||
*/
|
||||
|
|
@ -78,13 +62,6 @@ return [
|
|||
'blocking_time_period_check' => env('BLOCKING_TIME_PERIOD_CHECK', 30),
|
||||
'blocking_amount_events_authorized_during_period' => env('BLOCKING_AMOUNT_EVENTS_AUTHORIZED_DURING_PERIOD', 5),
|
||||
|
||||
/**
|
||||
* Account provisioning
|
||||
*/
|
||||
'provisioning_rc_file' => env('ACCOUNT_PROVISIONING_RC_FILE', ''),
|
||||
'provisioning_overwrite_all' => env('ACCOUNT_PROVISIONING_OVERWRITE_ALL', false),
|
||||
'provisioning_use_x_linphone_provisioning_header' => env('ACCOUNT_PROVISIONING_USE_X_LINPHONE_PROVISIONING_HEADER', true),
|
||||
|
||||
/**
|
||||
* /!\ Enable dangerous endpoints required for fallback
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'copyright' => env('INSTANCE_COPYRIGHT', null),
|
||||
'intro_registration' => env('INSTANCE_INTRO_REGISTRATION', null), // Can be Markdown formatted
|
||||
'confirmed_registration_text' => env('INSTANCE_CONFIRMED_REGISTRATION_TEXT', null), // Can be Markdown formatted
|
||||
'custom_theme' => env('INSTANCE_CUSTOM_THEME', false),
|
||||
];
|
||||
|
|
@ -30,7 +30,7 @@ class PasswordFactory extends Factory
|
|||
public function definition()
|
||||
{
|
||||
$account = Account::factory()->create();
|
||||
$realm = config('app.account_realm') ?? $account->domain;
|
||||
$realm = space()?->account_realm ?? $account->domain;
|
||||
|
||||
return [
|
||||
'account_id' => $account->id,
|
||||
|
|
@ -54,7 +54,7 @@ class PasswordFactory extends Factory
|
|||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
$account = Account::find($attributes['account_id']);
|
||||
$realm = config('app.account_realm') ?? $account->domain;
|
||||
$realm = space()?->account_realm ?? $account->domain;
|
||||
|
||||
return [
|
||||
'password' => hash('sha256', $account->username.':'.$realm.':testtest'),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,20 @@ class SpaceFactory extends Factory
|
|||
];
|
||||
}
|
||||
|
||||
public function local()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'host' => 'localhost',
|
||||
]);
|
||||
}
|
||||
|
||||
public function withoutProvisioningHeader()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'provisioning_use_linphone_provisioning_header' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function secondDomain()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
|
|
@ -43,6 +57,13 @@ class SpaceFactory extends Factory
|
|||
]);
|
||||
}
|
||||
|
||||
public function withRealm(string $realm)
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'account_realm' => $realm,
|
||||
]);
|
||||
}
|
||||
|
||||
public function expired()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('spaces', function (Blueprint $table) {
|
||||
$table->text('copyright_text')->nullable();
|
||||
$table->text('intro_registration_text')->nullable();
|
||||
$table->text('confirmed_registration_text')->nullable();
|
||||
|
||||
$table->string('newsletter_registration_address')->nullable();
|
||||
$table->string('account_proxy_registrar_address')->nullable();
|
||||
$table->string('account_realm')->nullable();
|
||||
|
||||
$table->text('custom_provisioning_entries')->nullable();
|
||||
$table->boolean('custom_provisioning_overwrite_all')->default(false);
|
||||
$table->boolean('provisioning_use_linphone_provisioning_header')->default(true);
|
||||
|
||||
$table->boolean('custom_theme')->default(false);
|
||||
$table->boolean('web_panel')->default(true);
|
||||
$table->boolean('public_registration')->default(true);
|
||||
$table->boolean('phone_registration')->default(true);
|
||||
$table->boolean('intercom_features')->default(false);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('spaces', function (Blueprint $table) {
|
||||
$table->dropColumn('copyright_text');
|
||||
$table->dropColumn('intro_registration_text');
|
||||
$table->dropColumn('confirmed_registration_text');
|
||||
|
||||
$table->dropColumn('newsletter_registration_address');
|
||||
$table->dropColumn('account_proxy_registrar_address');
|
||||
$table->dropColumn('account_realm');
|
||||
|
||||
$table->dropColumn('custom_provisioning_entries');
|
||||
$table->dropColumn('custom_provisioning_overwrite_all');
|
||||
$table->dropColumn('provisioning_use_linphone_provisioning_header');
|
||||
|
||||
$table->dropColumn('custom_theme');
|
||||
$table->dropColumn('web_panel');
|
||||
$table->dropColumn('public_registration');
|
||||
$table->dropColumn('phone_registration');
|
||||
$table->dropColumn('intercom_features');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -17,6 +17,6 @@
|
|||
|
||||
<p>GNU General Public Licence v3.0 (Licence)</p>
|
||||
|
||||
<p>{{ config('instance.copyright') }}</p>
|
||||
<p>{{ space()->instance_copyright }}</p>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<a href="{{ route('account.email.change') }}">Change my current account email</a>
|
||||
</p>
|
||||
|
||||
@if (config('app.phone_authentication'))
|
||||
@if (space()->phone_registration)
|
||||
<p>
|
||||
<i class="ph">phone</i>
|
||||
@if (!empty($account->phone))
|
||||
|
|
@ -66,8 +66,8 @@
|
|||
<p><i class="ph">user</i> Username: {{ $account->username }}</p>
|
||||
<p><i class="ph">globe-hemisphere-west</i> Domain: {{ $account->domain }}</p>
|
||||
|
||||
@if (!empty(config('app.proxy_registrar_address')))
|
||||
<p><i class="ph">lan</i> Proxy/registrar address: sip:{{ config('app.proxy_registrar_address') }}
|
||||
@if (!empty(space()?->account_proxy_registrar_address))
|
||||
<p><i class="ph">lan</i> Proxy/registrar address: sip:{{ space()?->account_proxy_registrar_address }}
|
||||
</p>
|
||||
@endif
|
||||
@if (!empty(config('app.transport_protocol_text')))
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ Registration can be achieve using several methods if they are correctly configur
|
|||
|
||||
## Email Registration
|
||||
|
||||
@if (!config('app.web_panel') || !config('app.public_registration'))
|
||||
*The feature is not enabled on this instance.*
|
||||
@endif
|
||||
|
||||
You can @if (config('app.web_panel') && config('app.public_registration')) [create an account using an email address]({{ route('account.register.email') }}) @else create an account using an email address @endif. The form requires you to provide an username and your email address.
|
||||
You can create an account using an email address. The form requires you to provide an username and your email address.
|
||||
|
||||
Once completed a confirmation email containing a unique link will be sent to the address. This link is used to activate your account, allowing you to finish the setup.
|
||||
|
||||
|
|
@ -24,11 +20,7 @@ Allow the creation of an account using a previously generated Account Creation T
|
|||
|
||||
## Phone Registration
|
||||
|
||||
@if (!config('app.phone_authentication'))
|
||||
*The feature is not enabled on this instance.*
|
||||
@endif
|
||||
|
||||
If enabled you can also @if (config('app.web_panel') && config('app.phone_authentication')) [create an account using a phone number]({{ route('account.register.phone') }}) @else create an account using a phone number @endif. You can also add an optional nickname to personnalize your SIP address. If not, your phone number will be used as a username.
|
||||
If enabled you can also create an account using a phone number. You can also add an optional nickname to personnalize your SIP address. If not, your phone number will be used as a username.
|
||||
|
||||
Once submitted, you will be asked to provide a unique pin code received by SMS to the phone number used during the registration.
|
||||
|
||||
|
|
@ -40,7 +32,7 @@ Once activated {{ $app_name }} will ask your to provide a password to finish you
|
|||
|
||||
To authenticate please fill in the username or phone number and password you provided during the registration phase.
|
||||
|
||||
If you forgot your password or didn't configured it, you can always recover your account using the recover password forms, using your @if (config('app.web_panel')) [email address]({{ route('account.recovery.show.email') }}) @else email address @endif or @if (config('app.web_panel') && config('app.phone_authentication')) [phone number]({{ route('account.recovery.show.phone') }}) @else phone number (not enabled) @endif. Once authenticated you will then be able to change your password.
|
||||
If you forgot your password or didn't configured it, you can always recover your account using the recover password forms, using your email address or phone number. Once authenticated you will then be able to change your password.
|
||||
|
||||
## Code based authentication
|
||||
|
||||
|
|
@ -48,7 +40,7 @@ If you forgot your password or didn't configured it, you can always recover your
|
|||
|
||||
# Account panel
|
||||
|
||||
Once authenticated you will get access to @if (config('app.web_panel')) [your account panel]({{ route('account.dashboard') }}) @else your account panel @endif.
|
||||
Once authenticated you will get access to your account panel.
|
||||
|
||||
## Generate an API Key
|
||||
|
||||
|
|
@ -56,22 +48,18 @@ You will be able to generate an API Key allowing you to use the {{ $app_name }}
|
|||
|
||||
## Change your email address
|
||||
|
||||
You can @if (config('app.web_panel')) [change your email address]({{ route('account.email.change') }}) @else change your email address @endif from the panel. A confirmation email containing a unique link will be sent to validate the new one.
|
||||
You can change your email address from the panel. A confirmation email containing a unique link will be sent to validate the new one.
|
||||
|
||||
## Change your password
|
||||
|
||||
Your password can also be changed from the @if (config('app.web_panel')) [password change form]({{ route('account.password.show') }}) @else password change form @endif. You can enable SHA-256 encrypted password when changing it (required for some clients).
|
||||
Your password can also be changed from the password change form. You can enable SHA-256 encrypted password when changing it (required for some clients).
|
||||
|
||||
## Delete your account
|
||||
|
||||
Your account can be deleted from the panel using the @if (config('app.web_panel')) [account deletion form]({{ route('account.delete') }}) @else account deletion form @endif. You must re-enter your full SIP address to confirm the deletion.
|
||||
Your account can be deleted from the panel using the account deletion form. You must re-enter your full SIP address to confirm the deletion.
|
||||
|
||||
## Devices management
|
||||
|
||||
@if (config('app.devices_management') == false)
|
||||
*The feature is not enabled on this instance.*
|
||||
@endif
|
||||
|
||||
From the devices management panel an admin will be able to list and delete the devices attached to a SIP account.
|
||||
|
||||
# Admin panel
|
||||
|
|
@ -102,10 +90,6 @@ The deletion of an account is definitive, all the database related data (passwor
|
|||
|
||||
### Create, edit and delete account types
|
||||
|
||||
@if (config('app.intercom_features') == false)
|
||||
*The feature is not enabled on this instance.*
|
||||
@endif
|
||||
|
||||
An adminisator can create, edit and delete account types. Those can be used to categorize accounts in clients, they are often used for Internet of Things related devices.
|
||||
|
||||
## Statistics
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
<section>
|
||||
<h1 style="margin-bottom: 3rem;"><i class="ph">hand-waving</i> Welcome on {{ config('app.name') }}</h1>
|
||||
|
||||
@if (config('instance.intro_registration'))
|
||||
@parsedown(config('instance.intro_registration'))
|
||||
@if (space()->intro_registration_text)
|
||||
@parsedown(space()->intro_registration_text)
|
||||
@endif
|
||||
|
||||
<form style="margin-top: 3rem; margin-bottom: 3rem;" method="POST" action="{{ route('account.authenticate') }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
<div>
|
||||
@if (config('app.phone_authentication'))
|
||||
@if (space()->phone_registration)
|
||||
<input placeholder="username or phone number" required="" name="username" type="text"
|
||||
value="{{ old('username') }}">
|
||||
<label for="username">Username or phone number</label>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
@include('parts.recovery')
|
||||
|
||||
@if (config('app.public_registration'))
|
||||
@if (space()->public_registration)
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
@include('parts.errors', ['name' => 'password_confirmation'])
|
||||
</div>
|
||||
|
||||
@if (!empty(config('app.newsletter_registration_address')))
|
||||
@if (!empty(config(space()?->newsletter_registration_address))
|
||||
<div class="large checkbox">
|
||||
<input id="newsletter" name="newsletter" type="checkbox" value="true">
|
||||
<label for="newsletter">I would like to subscribe to the newsletter</a></label>
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
|
||||
@include('parts.form.toggle', ['object' => $account, 'key' => 'activated', 'label' => 'Status', 'supporting' => 'Is the account enabled?'])
|
||||
|
||||
@if (config('app.intercom_features'))
|
||||
@if (space()?->intercom_features)
|
||||
<div class="select">
|
||||
<select name="dtmf_protocol">
|
||||
@foreach ($protocols as $value => $name)
|
||||
|
|
@ -212,7 +212,7 @@
|
|||
<a class="btn btn-light" href="{{ route('admin.account.provision', $account->id) }}">Generate a provision link</a>
|
||||
@endif
|
||||
|
||||
@if (config('app.intercom_features'))
|
||||
@if (space()?->intercom_features))
|
||||
<h2>Actions</h2>
|
||||
|
||||
@if ($account->dtmf_protocol)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<i class="ph">download-simple</i>
|
||||
Import Accounts
|
||||
</a>
|
||||
@if(config('app.intercom_features'))
|
||||
@if (space()?->intercom_features)
|
||||
<a class="btn btn-secondary" href="{{ route('admin.account.type.index') }}">
|
||||
<i class="ph">shapes</i>
|
||||
Types
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@
|
|||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.index') }}">Spaces</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">{{ $space->host }}</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Parameters</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
||||
{{ $space->host }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Space Administration</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
|
@ -16,7 +20,7 @@
|
|||
@include('admin.space.tabs')
|
||||
|
||||
<form method="POST"
|
||||
action="{{ route('admin.spaces.parameters.update', $space) }}"
|
||||
action="{{ route('admin.spaces.administration.update', $space) }}"
|
||||
accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('put')
|
||||
|
|
@ -38,6 +42,14 @@
|
|||
@include('parts.form.toggle', ['object' => $space, 'key' => 'super', 'label' => 'Super space', 'supporting' => 'All the admins in this Space will be Super Admins'])
|
||||
</div>
|
||||
|
||||
<h3 class="large">Interface</h3>
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'custom_theme', 'label' => 'Allow a custom CSS theme', 'supporting' => 'Check the README.md documentation to see how to setup the custom CSS file'])
|
||||
</div>
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'web_panel', 'label' => 'Enable the web interface', 'supporting' => 'It will actually disable this page, be careful'])
|
||||
</div>
|
||||
|
||||
<div class="large">
|
||||
<input class="btn" type="submit" value="Update">
|
||||
</div>
|
||||
102
flexiapi/resources/views/admin/space/configuration.blade.php
Normal file
102
flexiapi/resources/views/admin/space/configuration.blade.php
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
@if (auth()->user()->superAdmin)
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.index') }}">Spaces</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
||||
{{ $space->host }}
|
||||
</a>
|
||||
</li>
|
||||
@else
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.me') }}">
|
||||
{{ $space->host }}
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li class="breadcrumb-item active" aria-current="page">Space Configuration</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<header>
|
||||
<h1><i class="ph">globe-hemisphere-west</i> {{ $space->host }}</h1>
|
||||
</header>
|
||||
|
||||
@include('admin.space.tabs')
|
||||
|
||||
<form method="POST"
|
||||
action="{{ route('admin.spaces.configuration.update', $space) }}"
|
||||
accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('put')
|
||||
|
||||
<div class="large">
|
||||
<textarea name="copyright_text" id="copyright_text">{{ $space->copyright_text }}</textarea>
|
||||
<label for="copyright_text">Copyright text</label>
|
||||
@include('parts.errors', ['name' => 'copyright_text'])
|
||||
</div>
|
||||
|
||||
<div class="large">
|
||||
<textarea name="intro_registration_text" id="intro_registration_text">{{ $space->intro_registration_text }}</textarea>
|
||||
<label for="intro_registration_text">Registration introduction</label>
|
||||
<span class="supporting">Markdown text</span>
|
||||
@include('parts.errors', ['name' => 'intro_registration_text'])
|
||||
</div>
|
||||
|
||||
<div class="large">
|
||||
<textarea name="confirmed_registration_text" id="confirmed_registration_text">{{ $space->confirmed_registration_text }}</textarea>
|
||||
<label for="confirmed_registration_text">Confirmed registration text</label>
|
||||
<span class="supporting">Markdown text</span>
|
||||
@include('parts.errors', ['name' => 'confirmed_registration_text'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input name="newsletter_registration_address" id="newsletter_registration_address" placeholder="email@server.tld" type="email" value="{{ $space->newsletter_registration_address }}">
|
||||
<label for="newsletter_registration_address">Newsletter registration email address</label>
|
||||
<span class="supporting">An email will be sent to this address when someone register and join the newsletter</span>
|
||||
@include('parts.errors', ['name' => 'newsletter_registration_address'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input name="account_proxy_registrar_address" id="account_proxy_registrar_address" placeholder="server.tld" value="{{ $space->account_proxy_registrar_address }}">
|
||||
<label for="account_proxy_registrar_address">Account proxy registrar address</label>
|
||||
<span class="supporting">Will be used for informational purpose in the user panel and communication emails</span>
|
||||
@include('parts.errors', ['name' => 'account_proxy_registrar_address'])
|
||||
</div>
|
||||
|
||||
<h3 class="large">Provisioning</h3>
|
||||
|
||||
<div class="large">
|
||||
<textarea style="min-height: 200px;" name="custom_provisioning_entries" id="custom_provisioning_entries">{{ $space->custom_provisioning_entries }}</textarea>
|
||||
<label for="custom_provisioning_entries">Custom entries</label>
|
||||
<span class="supporting">In ini format, will complete the other settings</span>
|
||||
@include('parts.errors', ['name' => 'custom_provisioning_entries'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'custom_provisioning_overwrite_all', 'label' => 'Allow client settings to be overwritten by the provisioning ones'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'provisioning_use_linphone_provisioning_header', 'label' => 'Enforce X-Linphone-Provisioning header'])
|
||||
</div>
|
||||
|
||||
<h3 class="large">Space features</h3>
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'public_registration', 'label' => 'Allow public registration'])
|
||||
</div>
|
||||
<div
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'phone_registration', 'label' => 'Allow registration using phones'])
|
||||
</div>
|
||||
<div>
|
||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'intercom_features', 'label' => 'Enable intercom features'])
|
||||
</div>
|
||||
|
||||
<div class="large">
|
||||
<input class="btn" type="submit" value="Update">
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
|
|
@ -4,8 +4,12 @@
|
|||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.index') }}">Spaces</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">{{ $space->host }}</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Configuration</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
||||
{{ $space->host }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">App Configuration</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
|
||||
if (auth()->user()->superAdmin) {
|
||||
$items[route('admin.spaces.show', $space->id)] = 'Information';
|
||||
$items[route('admin.spaces.edit', $space->id)] = 'Configuration';
|
||||
$items[route('admin.spaces.parameters', $space->id)] = 'Parameters';
|
||||
$items[route('admin.spaces.administration', $space->id)] = 'Space Administration';
|
||||
$items[route('admin.spaces.edit', $space->id)] = 'App Configuration';
|
||||
} else if (auth()->user()->admin) {
|
||||
$items[route('admin.spaces.me')] = 'Information';
|
||||
}
|
||||
|
||||
$items[route('admin.spaces.configuration', $space->id)] = 'Space Configuration';
|
||||
@endphp
|
||||
|
||||
@include('parts.tabs', [
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Currently supported languages: @php
|
|||
|
||||
### Using the API Key
|
||||
|
||||
You can retrieve an API Key from @if (config('app.web_panel')) [your account panel]({{ route('account.login') }}) @else your account panel @endif or using <a href="#get-accountsmeapikey">the dedicated API endpoint</a>.
|
||||
You can retrieve an API Key from your account panel or using <a href="#get-accountsmeapikey">the dedicated API endpoint</a>.
|
||||
|
||||
**The generated API Key will be restricted to the IP that generates it and will be destroyed if not used after some times.**
|
||||
|
||||
|
|
@ -168,6 +168,20 @@ JSON parameters:
|
|||
* `max_account` integer, the maximum number of accounts configurable in the app, default to `0` (infinite)
|
||||
* `max_accounts` integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
||||
* `expire_at` date, the moment the space is expiring, default to `null` (never expire)
|
||||
* `copyright_text` text, the copyright text
|
||||
* `intro_registration_text` Markdown text, the main registration page text
|
||||
* `confirmed_registration_text` Markdown text, the text displayed in the registration email
|
||||
* `newsletter_registration_address`, the newsletter registration email address
|
||||
* `account_proxy_registrar_address`, the account proxy registrar address
|
||||
* `account_realm`, the default realm for the accounts, fallback to the domain if not set
|
||||
* `custom_provisioning_entries` text, the custom configuration used for the provisioning
|
||||
* `custom_provisioning_overwrite_all` boolean, allow the custom configuration to overwrite the default one
|
||||
* `provisioning_use_linphone_provisioning_header` boolean
|
||||
* `custom_theme` boolean, allow a custom CSS file to be loaded
|
||||
* `web_panel` boolean, the web panel switch
|
||||
* `public_registration` boolean, the public registration switch
|
||||
* `phone_registration` boolean, the phone registration switch
|
||||
* `intercom_features` boolean, the intercom features switch
|
||||
|
||||
### `PUT /spaces/{domain}`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
|
@ -190,6 +204,20 @@ JSON parameters:
|
|||
* `max_account` **required**, integer
|
||||
* `max_accounts` **required**,integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
||||
* `expire_at` **required**, date, the moment the space is expiring, set to `null` to never expire
|
||||
* `copyright_text` **required**, text, the copyright text
|
||||
* `intro_registration_text` **required**, Markdown text, the main registration page text
|
||||
* `confirmed_registration_text` **required**, Markdown text, the text displayed in the registration email
|
||||
* `newsletter_registration_address`, **required**, the newsletter registration email address
|
||||
* `account_proxy_registrar_address`, **required**, the account proxy registrar address
|
||||
* `account_realm`, **required**, the default realm for the accounts, fallback to the domain if not set
|
||||
* `custom_provisioning_entries` **required**, text, the custom configuration used for the provisioning
|
||||
* `custom_provisioning_overwrite_all` **required**, boolean, allow the custom configuration to overwrite the default one
|
||||
* `provisioning_use_linphone_provisioning_header` **required**, boolean
|
||||
* `custom_theme` **required**, boolean, allow a custom CSS file to be loaded
|
||||
* `web_panel` **required**, boolean, the web panel switch
|
||||
* `public_registration` **required**, boolean, the public registration switch
|
||||
* `phone_registration` **required**, boolean, the phone registration switch
|
||||
* `intercom_features` **required**, boolean, the intercom features switch
|
||||
|
||||
### `DELETE /spaces/{domain}`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,13 @@
|
|||
<title>{{ config('app.name') }}</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/style.css') }}">
|
||||
@if (config('instance.custom_theme') & file_exists(public_path('css/' . config('app.env') . '.style.css')))
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/' . config('app.env') . '.style.css') }}">
|
||||
|
||||
@php
|
||||
$space = space();
|
||||
@endphp
|
||||
|
||||
@if (space()?->custom_theme && file_exists(public_path('css/' . space()?->host . '.style.css')))
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/' . space()?->host . '.style.css') }}">
|
||||
@endif
|
||||
|
||||
<script src="{{ asset('scripts/utils.js') }}"></script>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
<body>
|
||||
<p>Hello,</p>
|
||||
<p>
|
||||
@if (config('instance.confirmed_registration_text'))
|
||||
@parsedown(config('instance.confirmed_registration_text'))
|
||||
@if (space()->confirmed_registration_text)
|
||||
{{ strip_tags(parsedown(space()->confirmed_registration_text)) }}
|
||||
@else
|
||||
Your SIP account has been successfully created.<br />
|
||||
You can now configure this account on any SIP-compatible application using the following parameters:<br />
|
||||
|
|
@ -17,8 +17,8 @@
|
|||
<b>Username:</b> {{ $account->username }}<br />
|
||||
<b>Domain:</b> {{ $account->domain }}<br />
|
||||
<br />
|
||||
@if (!empty(config('app.proxy_registrar_address')))
|
||||
<b>Proxy/registrar address: </b> sip:{{ config('app.proxy_registrar_address') }}<br />
|
||||
@if (!empty(space()?->account_proxy_registrar_address))
|
||||
<b>Proxy/registrar address: </b> sip:{{ space()?->account_proxy_registrar_address }}<br />
|
||||
@endif
|
||||
@if (!empty(config('app.transport_protocol_text')))
|
||||
<b>Transport: </b> {{ config('app.transport_protocol_text') }} <br />
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ Registration confirmed {{ config('app.name') }}
|
|||
|
||||
Hello,
|
||||
|
||||
@if (config('instance.confirmed_registration_text'))
|
||||
{{ strip_tags(parsedown(config('instance.confirmed_registration_text'))) }}
|
||||
@if (space()->confirmed_registration_text)
|
||||
{{ strip_tags(parsedown(space()->confirmed_registration_text)) }}
|
||||
@else
|
||||
Your SIP account has been successfully created.
|
||||
You can now configure this account on any SIP-compatible application using the following parameters:
|
||||
|
|
@ -13,8 +13,8 @@ You can now configure this account on any SIP-compatible application using the f
|
|||
Username: {{ $account->username }}
|
||||
Domain: {{ $account->domain }}
|
||||
|
||||
@if (!empty(config('app.proxy_registrar_address')))
|
||||
Proxy/registrar address: sip:{{ config('app.proxy_registrar_address') }}
|
||||
@if (!empty(space()?->account_proxy_registrar_address))
|
||||
Proxy/registrar address: sip:{{ space()?->account_proxy_registrar_address }}
|
||||
@endif
|
||||
@if (!empty(config('app.transport_protocol_text')))
|
||||
Transport: {{ config('app.transport_protocol_text') }}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
var account_infos = {
|
||||
sip: '{{ $account->identifier }}',
|
||||
username: '{{ $account->username }}',
|
||||
@if (!empty(config('app.proxy_registrar_address')))
|
||||
registrar_address: '{{ config('app.proxy_registrar_address') }}',
|
||||
@if (!empty(space()?->account_proxy_registrar_address))
|
||||
registrar_address: '{{ space()?->account_proxy_registrar_address }}',
|
||||
@endif
|
||||
domain: '{{ $account->domain }}'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Set or recover your password
|
||||
@endif
|
||||
using your <a href="{{ route('account.recovery.show.email') }}">Email address</a>
|
||||
@if (config('app.phone_authentication'))
|
||||
@if (space()->phone_registration)
|
||||
or your <a href="{{ route('account.recovery.show.phone') }}">Phone number</a>
|
||||
@endif
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@if(config('app.phone_authentication'))
|
||||
@if(space()->phone_registration)
|
||||
@include('parts.tabs', ['items' => [
|
||||
route('account.register.phone') => 'Phone registration',
|
||||
route('account.register.email') => 'Email registration',
|
||||
|
|
|
|||
|
|
@ -87,16 +87,16 @@ Route::name('provisioning.')->prefix('provisioning')->controller(ProvisioningCon
|
|||
});
|
||||
|
||||
Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
||||
if (config('app.public_registration')) {
|
||||
Route::middleware(['public_registration'])->group(function () {
|
||||
Route::redirect('register', 'register/email')->name('account.register');
|
||||
|
||||
if (config('app.phone_authentication')) {
|
||||
Route::middleware(['phone_registration'])->group(function () {
|
||||
Route::get('register/phone', 'Account\RegisterController@registerPhone')->name('account.register.phone');
|
||||
}
|
||||
});
|
||||
|
||||
Route::get('register/email', 'Account\RegisterController@registerEmail')->name('account.register.email');
|
||||
Route::post('accounts', 'Account\AccountController@store')->name('account.store');
|
||||
}
|
||||
});
|
||||
|
||||
Route::prefix('recovery')->controller(RecoveryController::class)->group(function () {
|
||||
Route::get('phone', 'showPhone')->name('account.recovery.show.phone');
|
||||
|
|
@ -115,14 +115,14 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
Route::post('/', 'store')->name('email.update');
|
||||
});
|
||||
|
||||
if (config('app.phone_authentication')) {
|
||||
Route::middleware(['phone_registration'])->group(function () {
|
||||
Route::prefix('phone')->controller(PhoneController::class)->group(function () {
|
||||
Route::get('change', 'change')->name('phone.change');
|
||||
Route::post('change', 'requestChange')->name('phone.request_change');
|
||||
Route::get('validate', 'validateChange')->name('phone.validate');
|
||||
Route::post('/', 'store')->name('phone.update');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Route::name('device.')->prefix('devices')->controller(DeviceController::class)->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
|
|
@ -156,13 +156,15 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
|
||||
Route::name('admin.')->prefix('admin')->middleware(['auth.admin', 'auth.check_blocked'])->group(function () {
|
||||
Route::get('space', 'Admin\SpaceController@me')->name('spaces.me');
|
||||
Route::get('spaces/{space}/configuration', 'Admin\SpaceController@configuration')->name('spaces.configuration');
|
||||
Route::put('spaces/{space}/configuration', 'Admin\SpaceController@configurationUpdate')->name('spaces.configuration.update');
|
||||
|
||||
Route::middleware(['auth.super_admin'])->group(function () {
|
||||
Route::resource('spaces', SpaceController::class);
|
||||
Route::get('spaces/delete/{id}', 'Admin\SpaceController@delete')->name('spaces.delete');
|
||||
|
||||
Route::get('spaces/{space}/parameters', 'Admin\SpaceController@parameters')->name('spaces.parameters');
|
||||
Route::put('spaces/{space}/parameters', 'Admin\SpaceController@parametersUpdate')->name('spaces.parameters.update');
|
||||
Route::get('spaces/{space}/administration', 'Admin\SpaceController@administration')->name('spaces.administration');
|
||||
Route::put('spaces/{space}/administration', 'Admin\SpaceController@administrationUpdate')->name('spaces.administration.update');
|
||||
|
||||
Route::name('phone_countries.')->controller(PhoneCountryController::class)->prefix('phone_countries')->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
|
|
@ -213,7 +215,7 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
Route::post('handle', 'handle')->name('handle');
|
||||
});
|
||||
|
||||
if (config('app.intercom_features')) {
|
||||
Route::middleware(['intercom_features'])->group(function () {
|
||||
Route::name('type.')->prefix('types')->controller(AccountTypeController::class)->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::get('create', 'create')->name('create');
|
||||
|
|
@ -238,7 +240,7 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
Route::get('{action_id}/delete', 'delete')->name('delete');
|
||||
Route::delete('{action_id}', 'destroy')->name('destroy');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Route::name('contact.')->prefix('{account}/contacts')->controller(AccountContactController::class)->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ class AccountJWTAuthenticationTest extends TestCase
|
|||
|
||||
$password = Password::factory()->create();
|
||||
|
||||
\App\Space::where('domain', $password->account->domain)->update(['host' => 'localhost']);
|
||||
|
||||
$bearer = 'authz_server="https://sso.test/", realm="sip.test.org"';
|
||||
|
||||
config()->set('services.jwt.rsa_public_key_pem', $this->serverPublicKeyPem);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ class AccountProvisioningTest extends TestCase
|
|||
|
||||
public function testBaseProvisioning()
|
||||
{
|
||||
Space::truncate();
|
||||
Space::factory()->local()->create();
|
||||
space(reload: true);
|
||||
|
||||
$this->get($this->route)->assertStatus(400);
|
||||
|
||||
$this->withHeaders([
|
||||
|
|
@ -51,7 +55,9 @@ class AccountProvisioningTest extends TestCase
|
|||
|
||||
public function testDisabledProvisioningHeader()
|
||||
{
|
||||
config()->set('app.provisioning_use_x_linphone_provisioning_header', false);
|
||||
Space::truncate();
|
||||
Space::factory()->local()->withoutProvisioningHeader()->create();
|
||||
space(reload: true);
|
||||
|
||||
$this->get($this->route)
|
||||
->assertStatus(200)
|
||||
|
|
@ -61,6 +67,10 @@ class AccountProvisioningTest extends TestCase
|
|||
|
||||
public function testDontProvisionHeaderDisabled()
|
||||
{
|
||||
Space::truncate();
|
||||
Space::factory()->local()->create();
|
||||
space(reload: true);
|
||||
|
||||
$account = Account::factory()->deactivated()->create();
|
||||
$account->generateApiKey();
|
||||
|
||||
|
|
|
|||
|
|
@ -581,14 +581,16 @@ class ApiAccountTest extends TestCase
|
|||
|
||||
public function testSimpleAccount()
|
||||
{
|
||||
$realm = 'realm.com';
|
||||
|
||||
Space::factory()->local()->withRealm($realm)->create();
|
||||
space(reload: true);
|
||||
|
||||
$password = Password::factory()->create();
|
||||
$password->account->activated = false;
|
||||
$password->account->generateApiKey();
|
||||
$password->account->save();
|
||||
|
||||
$realm = 'realm.com';
|
||||
config()->set('app.account_realm', $realm);
|
||||
|
||||
/**
|
||||
* Public information
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
namespace Tests\Feature;
|
||||
|
||||
use App\Password;
|
||||
use App\Space;
|
||||
|
||||
use Tests\TestCase;
|
||||
|
||||
|
|
@ -176,6 +177,10 @@ class ApiAuthenticationTest extends TestCase
|
|||
|
||||
public function testAuthenticationSHA265FromCLRTXT()
|
||||
{
|
||||
Space::truncate();
|
||||
Space::factory()->local()->create();
|
||||
space(reload: true);
|
||||
|
||||
$password = Password::factory()->clrtxt()->create();
|
||||
$response = $this->generateFirstResponse($password);
|
||||
|
||||
|
|
@ -204,7 +209,10 @@ class ApiAuthenticationTest extends TestCase
|
|||
public function testAuthenticationSHA265FromCLRTXTWithRealm()
|
||||
{
|
||||
$realm = 'realm.com';
|
||||
config()->set('app.account_realm', $realm);
|
||||
|
||||
Space::truncate();
|
||||
Space::factory()->local()->withRealm($realm)->create();
|
||||
space(reload: true);
|
||||
|
||||
$password = Password::factory()->clrtxt()->create();
|
||||
$response = $this->generateFirstResponse($password);
|
||||
|
|
@ -218,7 +226,7 @@ class ApiAuthenticationTest extends TestCase
|
|||
|
||||
$response = $this->withHeaders([
|
||||
'From' => 'sip:'.$password->account->identifier,
|
||||
'Authorization' => $this->generateDigest($password, $response, $hash),
|
||||
'Authorization' => $this->generateDigest($password, $response, $hash)
|
||||
])->json($this->method, $this->route);
|
||||
|
||||
$this->assertStringContainsString('algorithm=MD5', $response->headers->all()['www-authenticate'][0]);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ class ApiSpaceWithMiddlewareTest extends TestCaseWithSpaceMiddleware
|
|||
$admin->generateApiKey();
|
||||
config()->set('app.root_host', $admin->domain);
|
||||
|
||||
space(reload: true);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, 'http://' . $admin->domain . $this->accountRoute, [
|
||||
'username' => 'new',
|
||||
|
|
@ -62,6 +64,8 @@ class ApiSpaceWithMiddlewareTest extends TestCaseWithSpaceMiddleware
|
|||
->json('PUT', $this->route . '/' . $admin->domain, $space)
|
||||
->assertStatus(200);
|
||||
|
||||
space(reload: true);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->accountRoute, [
|
||||
'username' => 'new',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue