diff --git a/CHANGELOG.md b/CHANGELOG.md
index f56d6d6..8eccca6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ v1.6
- Fix FLEXIAPI-208 Add SMS templates documentation
- Fix FLEXIAPI-211 Add a JSON validation middleware + test
- Fix FLEXIAPI-212 Add CoTURN credentials support in the provisioning
+- Fix FLEXIAPI-213 Add TURN credentials support in the API as defined in draft-uberti-behave-turn-rest-00
v1.5
---
diff --git a/flexiapi/.env.example b/flexiapi/.env.example
index 28be017..dbab144 100644
--- a/flexiapi/.env.example
+++ b/flexiapi/.env.example
@@ -111,7 +111,6 @@ MAIL_SIGNATURE="The Example Team"
COTURN_SERVER_HOST= # IP or domain name
COTURN_SESSION_TTL_MINUTES=1440 # 60 * 24
COTURN_STATIC_AUTH_SECRET= # static-auth-secret in the coturn configuration
-COTURN_REALM= # realm in the coturn configuration, empty by default
# OVH SMS API variables
OVH_APP_KEY=
diff --git a/flexiapi/app/Helpers/Utils.php b/flexiapi/app/Helpers/Utils.php
index 640eb6c..95962a8 100644
--- a/flexiapi/app/Helpers/Utils.php
+++ b/flexiapi/app/Helpers/Utils.php
@@ -98,6 +98,30 @@ function markdownDocumentationView(string $view): string
);
}
+function hasCoTURNConfigured(): bool
+{
+ return config('app.coturn_session_ttl_minutes') > 0
+ && !empty(config('app.coturn_server_host'))
+ && !empty(config('app.coturn_static_auth_secret'));
+}
+
+function getCoTURNCredentials(): array
+{
+ $user = Str::random(8);
+ $secret = config('app.coturn_static_auth_secret');
+
+ $ttl = config('app.coturn_session_ttl_minutes') * 60;
+ $time = time() + $ttl;
+
+ $username = $time . ':' . Str::random(16);
+ $password = base64_encode(hash_hmac('sha1', $username, $secret, true));
+
+ return [
+ 'username' => $username,
+ 'password' => $password,
+ ];
+}
+
function parseSIP(string $sipAdress): array
{
return explode('@', \substr($sipAdress, 4));
diff --git a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
index 113adcf..7694fa3 100644
--- a/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
+++ b/flexiapi/app/Http/Controllers/Account/ProvisioningController.php
@@ -253,16 +253,8 @@ class ProvisioningController extends Controller
$authInfoIndex = 0;
// CoTURN
- if (config('app.coturn_session_ttl_minutes') > 0
- && !empty(config('app.coturn_server_host'))
- && !empty(config('app.coturn_static_auth_secret'))) {
- $user = 'foo';
- $secret = config('app.coturn_static_auth_secret');
-
- $ttl = config('app.coturn_session_ttl_minutes') * 60;
- $time = time() + $ttl;
- $username = $time . ':' . Str::random(16);
- $password = base64_encode(hash_hmac('sha1', $username, $secret, true));
+ if (hasCoTURNConfigured()) {
+ list($username, $password) = array_values(getCoTURNCredentials());
// net
$section = $xpath->query("//section[@name='net']")->item(0);
@@ -317,12 +309,6 @@ class ProvisioningController extends Controller
$entry = $dom->createElement('entry', $password);
$entry->setAttribute('name', 'passwd');
$section->appendChild($entry);
-
- if (!empty(config('app.coturn_realm'))) {
- $entry = $dom->createElement('entry', config('app.coturn_realm'));
- $entry->setAttribute('name', 'realm');
- $section->appendChild($entry);
- }
}
foreach ($passwords as $password) {
diff --git a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
index 641595f..a123118 100644
--- a/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
+++ b/flexiapi/app/Http/Controllers/Api/Account/AccountController.php
@@ -60,6 +60,27 @@ class AccountController extends Controller
]);
}
+ /**
+ * Get services credentials
+ */
+ public function turnService(Request $request)
+ {
+ if (hasCoturnConfigured()) {
+ list($username, $password) = array_values(getCoTURNCredentials());
+
+ return [
+ 'username' => $username,
+ 'password' => $password,
+ 'ttl' => config('app.coturn_session_ttl_minutes') * 60,
+ 'uris' => [
+ 'turn:' . config('app.coturn_server_host'),
+ ]
+ ];
+ }
+
+ return abort(404, 'No TURN service configured');
+ }
+
/**
* /!\ Dangerous endpoint, disabled by default
*/
diff --git a/flexiapi/config/app.php b/flexiapi/config/app.php
index 495bbc7..3521378 100644
--- a/flexiapi/config/app.php
+++ b/flexiapi/config/app.php
@@ -56,7 +56,6 @@ return [
'coturn_server_host' => env('COTURN_SERVER_HOST', null),
'coturn_session_ttl_minutes' => (int)env('COTURN_SESSION_TTL_MINUTES', 60 * 24),
'coturn_static_auth_secret' => env('COTURN_STATIC_AUTH_SECRET', null),
- 'coturn_realm' => env('COTURN_REALM', null),
/**
* External interfaces
diff --git a/flexiapi/resources/views/api/documentation_markdown.blade.php b/flexiapi/resources/views/api/documentation_markdown.blade.php
index 58b5e7f..f6e01f2 100644
--- a/flexiapi/resources/views/api/documentation_markdown.blade.php
+++ b/flexiapi/resources/views/api/documentation_markdown.blade.php
@@ -364,6 +364,11 @@ This endpoint is also setting the API Key as a Cookie.
Retrieve the account information.
+### `GET /accounts/me/services/turn`
+User
+
+If configured, returns valid TURN credentials following the [draft-uberti-behave-turn-rest-00 IEFT Draft](https://datatracker.ietf.org/doc/html/draft-uberti-behave-turn-rest-00).
+
### `GET /accounts/me/provision`
User
diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php
index 56e2f09..2377428 100644
--- a/flexiapi/routes/api.php
+++ b/flexiapi/routes/api.php
@@ -68,6 +68,8 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
Route::prefix('accounts/me')->group(function () {
Route::get('api_key', 'Api\Account\ApiKeyController@generate')->middleware('cookie', 'cookie.encrypt');
+ Route::get('services/turn', 'Api\Account\AccountController@turnService');
+
Route::get('/', 'Api\Account\AccountController@show');
Route::delete('/', 'Api\Account\AccountController@delete');
Route::get('provision', 'Api\Account\AccountController@provision');
diff --git a/flexiapi/tests/Feature/AccountProvisioningTest.php b/flexiapi/tests/Feature/AccountProvisioningTest.php
index feab65a..4a56dd7 100644
--- a/flexiapi/tests/Feature/AccountProvisioningTest.php
+++ b/flexiapi/tests/Feature/AccountProvisioningTest.php
@@ -351,6 +351,10 @@ class AccountProvisioningTest extends TestCase
$host = 'coturn.tld';
$realm = 'realm.tld';
+ $this->keyAuthenticated($account)
+ ->get('/api/accounts/me/services/turn')
+ ->assertStatus(404);
+
config()->set('app.coturn_server_host', $host);
config()->set('app.coturn_static_auth_secret', 'secret');
@@ -364,21 +368,13 @@ class AccountProvisioningTest extends TestCase
->assertSee($host)
->assertSee('nat_policy_ref')
->assertSee('stun_server_username')
- ->assertSee('nat_policy_0')
- ->assertDontSee('realm')
- ->assertDontSee($realm);
+ ->assertSee('nat_policy_0');
- config()->set('app.coturn_realm', $realm);
-
- $response = $this->withHeaders([
- 'x-linphone-provisioning' => true,
- ])
- ->keyAuthenticated($account)
- ->get($this->accountRoute)
+ $this->keyAuthenticated($account)
+ ->get('/api/accounts/me/services/turn')
->assertStatus(200)
- ->assertHeader('Content-Type', 'application/xml')
- ->assertSee($host)
- ->assertSee('realm')
- ->assertSee($realm);
+ ->assertJson([
+ 'ttl' => config()->get('app.coturn_session_ttl_minutes') * 60
+ ]);
}
}