diff --git a/web/app/Helpers/COMHelper.php b/web/app/Helpers/COMHelper.php new file mode 100644 index 0000000..404f1cd --- /dev/null +++ b/web/app/Helpers/COMHelper.php @@ -0,0 +1,15 @@ +ip(); + $whitelistedIps = explode(';', WebsiteConfiguration::where('name', 'WhitelistedIPs')->first()->value); + + return in_array($ip, $whitelistedIps); + } + + public static function isAccessKeyValid($request) { + $accessKey = WebsiteConfiguration::where('name', 'ComputeServiceAccessKey')->first()->value; + + return ($request->header('AccessKey') == $accessKey); + } + + public static function hasAllAccess($request) { + if(COMHelper::isCOM()) return true; + if(GridHelper::isIpWhitelisted($request) && GridHelper::isAccessKeyValid($request)) return true; + + return false; + } +} diff --git a/web/app/Helpers/JSON.php b/web/app/Helpers/JSON.php new file mode 100644 index 0000000..9a6f6db --- /dev/null +++ b/web/app/Helpers/JSON.php @@ -0,0 +1,21 @@ +header('Content-Type', 'application/json'); + } +} diff --git a/web/app/Http/Controllers/AppSettings.php b/web/app/Http/Controllers/AppSettings.php new file mode 100644 index 0000000..6f3ea66 --- /dev/null +++ b/web/app/Http/Controllers/AppSettings.php @@ -0,0 +1,106 @@ + '', + 'Fast' => 'F', + 'Dynamic' => 'DF', + 'Synchronised' => 'SF' + ]; + + /** + * A list of flag types + * + * @var array + */ + protected $types = [ + 'Log' => 'Log', + 'Int' => 'Int', + 'String' => 'String', + 'Boolean' => 'Flag' + ]; + + /** + * Returns a JSON array with the error code and message. + * + * @return Response + */ + private function error($data, $code = 400) + { + return response(['errors' => [$data]], 400); + } + + /** + * Returns a JSON array of settings for the specified bucket. + * + * @param \Illuminate\Http\Request $request + * @param string $bucketName + * @return Response + */ + public function getBucket(Request $request, $bucketName) + { + $primaryBucket = Fbucket::where('name', $bucketName); + + if($primaryBucket->exists()) { + $primaryBucket = $primaryBucket->first(); + + $bucketIds = [ $primaryBucket->id ]; + $bucketIds = array_merge($bucketIds, json_decode($primaryBucket->inheritedGroupIds)); + + if($primaryBucket->protected == 1 && !GridHelper::hasAllAccess($request)) { + return $this->error([ + 'code' => 2, + 'message' => 'You do not have access to this bucket.' + ], 401); + } + + /* */ + + $flags = []; + + foreach($bucketIds as $bucket) { + $fflags = FFlag::where('bucketId', $bucket)->get(); + + foreach($fflags as $flag) { + $prefix = $this->prefixes[$flag->type]; + $dataType = $this->types[$flag->dataType]; + + $name = ''; + if($prefix != 'Unscoped') { + $name = ($prefix . $dataType); + } + + $name .= $flag->name; + + $flags[$name] = $flag->value; + } + } + + return JSON::EncodeResponse($flags); + } else { + return $this->error([ + 'code' => 1, + 'message' => 'The requested bucket does not exist.' + ]); + } + } + +} diff --git a/web/app/Models/FFlag.php b/web/app/Models/FFlag.php index 40701e2..e1ef304 100644 --- a/web/app/Models/FFlag.php +++ b/web/app/Models/FFlag.php @@ -7,5 +7,19 @@ use Illuminate\Database\Eloquent\Model; class FFlag extends Model { + /** + * The database connection that should be used by the migration. + * + * @var string + */ + protected $connection = 'mysql-fflag'; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'fflags'; + use HasFactory; } diff --git a/web/app/Models/FastGroup.php b/web/app/Models/FastGroup.php deleted file mode 100644 index b2041d7..0000000 --- a/web/app/Models/FastGroup.php +++ /dev/null @@ -1,11 +0,0 @@ -namespace($this->namespace) ->group(base_path('routes/apis.php')); + Route::domain('clientsettings.api.' . env('APP_URL')) + ->middleware('api') + ->namespace($this->namespace) + ->group(base_path('routes/appsettings.php')); + Route::domain('impulse.' . env('APP_URL')) ->middleware('admin') ->namespace($this->namespace) diff --git a/web/config/database.php b/web/config/database.php index 66d8670..a8f2466 100644 --- a/web/config/database.php +++ b/web/config/database.php @@ -15,7 +15,7 @@ return [ | */ - 'default' => env('DB_CONNECTION', 'mysql'), + 'default' => env('DB_CONNECTION', 'mysql-primary'), /* |-------------------------------------------------------------------------- @@ -38,17 +38,37 @@ return [ 'sqlite' => [ 'driver' => 'sqlite', 'url' => env('DATABASE_URL'), - 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'database' => env('DB_PRIMARY_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), ], - 'mysql' => [ + 'mysql-primary' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'forge'), + 'database' => env('DB_PRIMARY_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mysql-fflag' => [ + 'driver' => 'mysql', + 'url' => env('DATABASE_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_FFLAG_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), @@ -68,7 +88,7 @@ return [ 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), - 'database' => env('DB_DATABASE', 'forge'), + 'database' => env('DB_PRIMARY_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', @@ -83,7 +103,7 @@ return [ 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '1433'), - 'database' => env('DB_DATABASE', 'forge'), + 'database' => env('DB_PRIMARY_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', diff --git a/web/database/migrations/2021_12_15_224204_create_fflags_table.php b/web/database/migrations/2021_12_15_224204_create_fflags_table.php index 6ba9868..d460fae 100644 --- a/web/database/migrations/2021_12_15_224204_create_fflags_table.php +++ b/web/database/migrations/2021_12_15_224204_create_fflags_table.php @@ -6,6 +6,13 @@ use Illuminate\Support\Facades\Schema; class CreateFflagsTable extends Migration { + /** + * The database connection that should be used by the migration. + * + * @var string + */ + protected $connection = 'mysql-fflag'; + /** * Run the migrations. * @@ -19,7 +26,7 @@ class CreateFflagsTable extends Migration $table->string('value'); $table->enum('dataType', ['Log', 'Int', 'String', 'Boolean']); $table->enum('type', ['Unscoped', 'Fast', 'Dynamic', 'Synchronised']); - $table->bigInteger('groupId'); + $table->bigInteger('bucketId'); $table->timestamps(); }); } diff --git a/web/database/migrations/2021_12_16_011850_create_fastgroups_table.php b/web/database/migrations/2021_12_16_011850_create_fbuckets_table.php similarity index 66% rename from web/database/migrations/2021_12_16_011850_create_fastgroups_table.php rename to web/database/migrations/2021_12_16_011850_create_fbuckets_table.php index 98339ba..08a0141 100644 --- a/web/database/migrations/2021_12_16_011850_create_fastgroups_table.php +++ b/web/database/migrations/2021_12_16_011850_create_fbuckets_table.php @@ -4,8 +4,15 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateFastgroupsTable extends Migration +class CreateFbucketsTable extends Migration { + /** + * The database connection that should be used by the migration. + * + * @var string + */ + protected $connection = 'mysql-fflag'; + /** * Run the migrations. * @@ -13,7 +20,7 @@ class CreateFastgroupsTable extends Migration */ public function up() { - Schema::create('fastgroups', function (Blueprint $table) { + Schema::create('fbuckets', function (Blueprint $table) { $table->id(); $table->string('name'); $table->boolean('protected')->default(false); @@ -29,6 +36,6 @@ class CreateFastgroupsTable extends Migration */ public function down() { - Schema::dropIfExists('fastgroups'); + Schema::dropIfExists('fbuckets'); } } diff --git a/web/database/seeders/FFlagSeeder.php b/web/database/seeders/FFlagSeeder.php index 4b02ad1..7a323e1 100644 --- a/web/database/seeders/FFlagSeeder.php +++ b/web/database/seeders/FFlagSeeder.php @@ -5,7 +5,7 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; use App\Models\FFlag; -use App\Models\Fastgroup; +use App\Models\Fbucket; class FFlagSeeder extends Seeder { @@ -16,41 +16,41 @@ class FFlagSeeder extends Seeder */ public function run() { - $appSettingsCommon = Fastgroup::create([ + $appSettingsCommon = Fbucket::create([ 'name' => 'AppSettingsCommon', 'protected' => true ]); - $clientAppSettings = Fastgroup::create([ + $clientAppSettings = Fbucket::create([ 'name' => 'ClientAppSettings', 'inheritedGroupIds' => json_encode([ $appSettingsCommon->id ]) ]); - $cloudAppSettings = Fastgroup::create([ + $cloudAppSettings = Fbucket::create([ 'name' => 'CloudCompute', 'protected' => true, 'inheritedGroupIds' => json_encode([ $appSettingsCommon->id ]) ]); - $clientSharedSettings = Fastgroup::create([ + $clientSharedSettings = Fbucket::create([ 'name' => 'ClientSharedSettings' ]); - $arbiterAppSettings = Fastgroup::create([ + $arbiterAppSettings = Fbucket::create([ 'name' => 'Arbiter' ]); - $bootstrapperCommon = Fastgroup::create([ + $bootstrapperCommon = Fbucket::create([ 'name' => 'BootstrapperCommon', 'protected' => true ]); - $windowsBootstrapperSettings = Fastgroup::create([ + $windowsBootstrapperSettings = Fbucket::create([ 'name' => 'WindowsBootstrapperSettings', 'inheritedGroupIds' => json_encode([ $bootstrapperCommon->id ]) ]); - $windowsStudioBootstrapperSettings = Fastgroup::create([ + $windowsStudioBootstrapperSettings = Fbucket::create([ 'name' => 'WindowsStudioBootstrapperSettings', 'inheritedGroupIds' => json_encode([ $bootstrapperCommon->id ]) ]); diff --git a/web/database/seeders/WebConfigurationSeeder.php b/web/database/seeders/WebConfigurationSeeder.php index d3021d7..e70fa28 100644 --- a/web/database/seeders/WebConfigurationSeeder.php +++ b/web/database/seeders/WebConfigurationSeeder.php @@ -23,5 +23,15 @@ class WebConfigurationSeeder extends Seeder 'password' => '@bs0lut3lyM@55!v3P@55w0rd' ]) ]); // please please please please please please please change the default password + + WebsiteConfiguration::create([ + 'name' => 'ComputeServiceAccessKey', + 'value' => '92a6ac6b-7167-49b1-9ccd-079820ac892b' + ]); // change this as well + + WebsiteConfiguration::create([ + 'name' => 'WhitelistedIPs', + 'value' => '127.0.0.1' + ]); } } diff --git a/web/routes/appsettings.php b/web/routes/appsettings.php new file mode 100644 index 0000000..a33712a --- /dev/null +++ b/web/routes/appsettings.php @@ -0,0 +1,28 @@ +header('Cache-Control', 'private') + ->header('Content-Type', 'application/json; charset=utf-8'); +}); \ No newline at end of file