diff --git a/src/Base.php b/src/Base.php
index adf32ad..529396a 100644
--- a/src/Base.php
+++ b/src/Base.php
@@ -6,6 +6,11 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Slack\Models\{Channel,Enterprise,Team,User};
+use App\Models\Channel as AppChannel;
+use App\Models\Enterprise as AppEnterprise;
+use App\Models\Team as AppTeam;
+use App\Models\User as AppUser;
+
/**
* Class Base - is a Base to all incoming Slack POST requests
*
@@ -43,7 +48,9 @@ abstract class Base
*/
final public function channel(bool $create=FALSE): ?Channel
{
- $o = Channel::firstOrNew(
+ $class = class_exists(AppChannel::class) ? AppChannel::class : Channel::class;
+
+ $o = $class::firstOrNew(
[
'channel_id'=>$this->channel_id,
]);
@@ -59,7 +66,9 @@ abstract class Base
final public function enterprise(): Enterprise
{
- return Enterprise::firstOrNew(
+ $class = class_exists(AppEnterprise::class) ? AppEnterprise::class : Enterprise::class;
+
+ return $class::firstOrNew(
[
'enterprise_id'=>$this->enterprise_id
]);
@@ -73,7 +82,9 @@ abstract class Base
*/
final public function team(bool $any=FALSE): ?Team
{
- $o = Team::firstOrNew(
+ $class = class_exists(AppTeam::class) ? AppTeam::class : Team::class;
+
+ $o = $class::firstOrNew(
[
'team_id'=>$this->team_id
]);
@@ -94,7 +105,9 @@ abstract class Base
*/
final public function user(): User
{
- $o = User::firstOrNew(
+ $class = class_exists(AppUser::class) ? AppUser::class : User::class;
+
+ $o = $class::firstOrNew(
[
'user_id'=>$this->user_id,
]);
diff --git a/src/Client/Payload.php b/src/Client/Payload.php
index d415340..0ab06a8 100644
--- a/src/Client/Payload.php
+++ b/src/Client/Payload.php
@@ -17,9 +17,9 @@ class Payload implements \ArrayAccess, \JsonSerializable
*
* @param array $data The payload data.
*/
- public function __construct(array $data)
+ public function __construct(array $data,bool $key=FALSE)
{
- $this->data = $data;
+ $this->data = $key ? ['payload'=>$data ] : $data;
}
/**
diff --git a/src/Event/Factory.php b/src/Event/Factory.php
index a2817c0..c2e088a 100644
--- a/src/Event/Factory.php
+++ b/src/Event/Factory.php
@@ -15,14 +15,14 @@ class Factory {
* @var array event type to event class mapping
*/
public const map = [
- 'app_home_opened'=>AppHomeOpened::class,
- 'member_joined_channel'=>MemberJoinedChannel::class,
- 'channel_left'=>ChannelLeft::class,
- 'group_left'=>GroupLeft::class,
- 'message'=>Message::class,
- 'reaction_added'=>ReactionAdded::class,
- 'pin_added'=>PinAdded::class,
- 'pin_removed'=>PinRemoved::class,
+ 'app_home_opened' => AppHomeOpened::class,
+ 'member_joined_channel' => MemberJoinedChannel::class,
+ 'channel_left' => ChannelLeft::class,
+ 'group_left' => GroupLeft::class,
+ 'message' => Message::class,
+ 'reaction_added' => ReactionAdded::class,
+ 'pin_added' => PinAdded::class,
+ 'pin_removed' => PinRemoved::class,
];
/**
diff --git a/src/Http/Controllers/EventsController.php b/src/Http/Controllers/EventsController.php
new file mode 100644
index 0000000..8ecdeb3
--- /dev/null
+++ b/src/Http/Controllers/EventsController.php
@@ -0,0 +1,30 @@
+all(),TRUE));
+ Log::info(sprintf('%s:Dispatching Event [%s]',static::LOGKEY,get_class($event)));
+ event($event);
+
+ return response('Event Processed',200);
+ }
+}
diff --git a/src/Http/Controllers/SlackAppController.php b/src/Http/Controllers/SlackAppController.php
index c35ea20..dd29500 100644
--- a/src/Http/Controllers/SlackAppController.php
+++ b/src/Http/Controllers/SlackAppController.php
@@ -14,7 +14,7 @@ use Slack\Models\{Enterprise,Team,Token,User};
class SlackAppController extends Controller
{
- private const LOGKEY = 'CSA';
+ protected const LOGKEY = 'CSA';
private const slack_authorise_url = 'https://slack.com/oauth/v2/authorize';
private const slack_oauth_url = 'https://slack.com/api/oauth.v2.access';
@@ -39,7 +39,7 @@ class SlackAppController extends Controller
public function home()
{
- return sprintf('Hi, for instructions on how to install me, please reach out to @deon.');
+ return sprintf('Hi, for instructions on how to install me, please reach out to %s.',config('slack.app_admin','Your slack admin'));
}
public function setup()
@@ -54,7 +54,7 @@ class SlackAppController extends Controller
* @return string
* @throws \GuzzleHttp\Exception\GuzzleException
*/
- public function install(Request $request)
+ public function install(Request $request,bool $oauth=FALSE)
{
if (! config('slack.client_id') OR ! config('slack.client_secret'))
abort(403,'Slack ClientID or Secret not set');
@@ -158,7 +158,7 @@ class SlackAppController extends Controller
$so->admin_id = $uo->id;
$so->save();
- return sprintf('All set up! Head back to your slack instance %s.',$so->description);
+ return $oauth ? $output : sprintf('All set up! Head back to your slack instance %s.',$so->description);
}
/**
diff --git a/src/Http/Middleware/CheckRequest.php b/src/Http/Middleware/CheckRequest.php
new file mode 100644
index 0000000..951450d
--- /dev/null
+++ b/src/Http/Middleware/CheckRequest.php
@@ -0,0 +1,81 @@
+path()),['m'=>__METHOD__]);
+
+ // For app installs, we have nothing to check.
+ if (in_array($request->path(),config('slack.bypass_routes')))
+ return $next($request);
+
+ switch ($request->path()) {
+ // For slashcmd full validation is done in the controller
+ case 'api/slashcmd':
+ return $next($request);
+
+ case 'api/event':
+ // URL Verification
+ if ($request->input('type') === 'url_verification') {
+ Log::debug(sprintf('%s:Responding directly to URL Verification',static::LOGKEY),['m'=>__METHOD__,'r'=>$request->all()]);
+ return response($request->input('challenge'),200);
+ }
+
+ $event = EventFactory::make(new Payload($request->all(),TRUE));
+ break;
+
+ case 'api/imsgopt':
+ $event = OptionsFactory::make($request);
+ break;
+
+ case 'api/imsg':
+ $event = InteractiveFactory::make($request);
+ break;
+
+ default:
+ // Quietly die if we got here.
+ return response('',444);
+ }
+
+ // Ignore events for inactive workspaces
+ if ($event->enterprise_id AND (! $event->enterprise()->active)) {
+ Log::notice(sprintf('%s:IGNORING post, Enterprise INACTIVE [%s]',static::LOGKEY,$event->enterprise_id),['m'=>__METHOD__]);
+
+ // Quietly die if the team is not active
+ return response('',200);
+
+ } elseif ((! $event->enterprise_id) AND ((! $event->team()) OR (! $event->team()->active))) {
+ Log::notice(sprintf('%s:IGNORING post, Team INACTIVE [%s]',static::LOGKEY,$event->team_id),['m'=>__METHOD__]);
+
+ // Quietly die if the team is not active
+ return response('',200);
+
+ } else {
+ Log::debug(sprintf('%s:Incoming Request Allowed',static::LOGKEY),['m'=>__METHOD__,'e'=>$event->enterprise_id,'t'=>$event->team_id,'eo'=>$event->enterprise()->id,'to'=>$event->team()]);
+
+ return $next($request);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Http/Middleware/CheckSignature.php b/src/Http/Middleware/CheckSignature.php
new file mode 100644
index 0000000..d4fbdb8
--- /dev/null
+++ b/src/Http/Middleware/CheckSignature.php
@@ -0,0 +1,69 @@
+path(),config('slack.bypass_routes'))) {
+ // get the remote sign
+ $remote_signature = $request->header('X-Slack-Signature');
+ Log::info(sprintf('%s:Incoming request - check slack SIGNATURE [%s]',static::LOGKEY,$remote_signature),['m'=>__METHOD__]);
+
+ // Load the secret, you also can load it from env(YOUR_OWN_SLACK_SECRET)
+ $secret = config('slack.signing_secret');
+
+ $body = $request->getContent();
+
+ // Compare timestamp with the local time, according to the slack official documents
+ // the gap should under 5 minutes
+ // @codeCoverageIgnoreStart
+ if (! $timestamp = $request->header('X-Slack-Request-Timestamp')) {
+ Log::alert(sprintf('%s:No slack timestamp - aborting...',static::LOGKEY),['m'=>__METHOD__]);
+
+ return response('',444);
+ }
+
+ if (($x=Carbon::now()->diffInMinutes(Carbon::createFromTimestamp($timestamp))) > 5) {
+ Log::alert(sprintf('%s:Invalid slack timestamp [%d]',static::LOGKEY,$x),['m'=>__METHOD__]);
+
+ return response('',444);
+ }
+ // @codeCoverageIgnoreEnd
+
+ // generate the string base
+ $sig_basestring = sprintf('%s:%s:%s',Base::signature_version,$timestamp,$body);
+
+ // generate the local sign
+ $hash = hash_hmac('sha256',$sig_basestring,$secret);
+ $local_signature = sprintf('%s=%s',Base::signature_version,$hash);
+
+ // check two signs, if not match, throw an error
+ if ($remote_signature !== $local_signature) {
+ Log::alert(sprintf('%s:Invalid slack signature [%s]',static::LOGKEY,$remote_signature),['m'=>__METHOD__]);
+
+ return response('',444);
+ }
+ }
+
+ return $next($request);
+ }
+}
diff --git a/src/Models/Channel.php b/src/Models/Channel.php
index 6459054..469696c 100644
--- a/src/Models/Channel.php
+++ b/src/Models/Channel.php
@@ -4,14 +4,13 @@ namespace Slack\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
-use Leenooks\Traits\ScopeActive;
+use Slack\Traits\ScopeActive;
class Channel extends Model
{
use ScopeActive;
protected $fillable = ['team_id','channel_id','name','active'];
- protected $table = 'slack_channels';
/* RELATIONS */
diff --git a/src/Models/Enterprise.php b/src/Models/Enterprise.php
index e7bb636..fc057c8 100644
--- a/src/Models/Enterprise.php
+++ b/src/Models/Enterprise.php
@@ -3,14 +3,13 @@
namespace Slack\Models;
use Illuminate\Database\Eloquent\Model;
-use Leenooks\Traits\ScopeActive;
+use Slack\Traits\ScopeActive;
class Enterprise extends Model
{
use ScopeActive;
protected $fillable = ['enterprise_id'];
- protected $table = 'slack_enterprises';
/* RELATIONS */
diff --git a/src/Models/Team.php b/src/Models/Team.php
index 4eb5a7f..18d4aca 100644
--- a/src/Models/Team.php
+++ b/src/Models/Team.php
@@ -3,15 +3,14 @@
namespace Slack\Models;
use Illuminate\Database\Eloquent\Model;
-use Leenooks\Traits\ScopeActive;
use Slack\API;
+use Slack\Traits\ScopeActive;
class Team extends Model
{
use ScopeActive;
protected $fillable = ['team_id'];
- protected $table = 'slack_teams';
/* RELATIONS */
diff --git a/src/Models/Token.php b/src/Models/Token.php
index bd49c22..9dec68f 100644
--- a/src/Models/Token.php
+++ b/src/Models/Token.php
@@ -4,14 +4,12 @@ namespace Slack\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
-use Leenooks\Traits\ScopeActive;
+use Slack\Traits\ScopeActive;
class Token extends Model
{
use ScopeActive;
- protected $table = 'slack_tokens';
-
/* RELATIONS */
public function team()
diff --git a/src/Models/User.php b/src/Models/User.php
index 5053f27..15fdd15 100644
--- a/src/Models/User.php
+++ b/src/Models/User.php
@@ -4,16 +4,15 @@ namespace Slack\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
-use Leenooks\Traits\ScopeActive;
+use Slack\Traits\ScopeActive;
class User extends Model
{
use ScopeActive;
- private const LOGKEY = '-MU';
+ protected const LOGKEY = '-MU';
protected $fillable = ['user_id'];
- protected $table = 'slack_users';
/* RELATIONS */
diff --git a/src/Providers/SlackServiceProvider.php b/src/Providers/SlackServiceProvider.php
index 2e50ba2..7414b92 100644
--- a/src/Providers/SlackServiceProvider.php
+++ b/src/Providers/SlackServiceProvider.php
@@ -9,6 +9,9 @@ use Slack\API;
use Slack\Channels\SlackBotChannel;
use Slack\Console\Commands\SlackSocketClient;
+/**
+ * @todo For Lumen installs, this service provider is not required?
+ */
class SlackServiceProvider extends ServiceProvider
{
/**
diff --git a/src/Traits/ScopeActive.php b/src/Traits/ScopeActive.php
new file mode 100644
index 0000000..1866a9e
--- /dev/null
+++ b/src/Traits/ScopeActive.php
@@ -0,0 +1,17 @@
+where($this->getTable().'.active',TRUE);
+ }
+}
diff --git a/src/config/slack.php b/src/config/slack.php
index 1649579..67ddc12 100644
--- a/src/config/slack.php
+++ b/src/config/slack.php
@@ -6,4 +6,7 @@ return [
'client_secret' => env('SLACK_CLIENT_SECRET',NULL),
'signing_secret' => env('SLACK_SIGNING_SECRET',NULL),
'register_notification' => env('SLACK_REGISTER_NOTIFICATION',TRUE),
+
+ // Our routes that we dont check for signatures
+ 'bypass_routes' => ['/','slack-install-button','slack-install'],
];
diff --git a/src/routes.php b/src/routes.php
index c878215..90f2249 100644
--- a/src/routes.php
+++ b/src/routes.php
@@ -4,14 +4,28 @@ $routeConfig = [
'namespace' => 'Slack\Http\Controllers',
];
-app('router')->group($routeConfig, function ($router) {
- $router->get('slack-install-button', [
- 'uses' => 'SlackAppController@button',
- 'as' => 'slack-install-button',
- ]);
+app('router')
+ ->group($routeConfig, function ($router) {
+ $router->get('slack-install-button', [
+ 'uses' => 'SlackAppController@button',
+ 'as' => 'slack-install-button',
+ ]);
- $router->get('slack-install', [
- 'uses' => 'SlackAppController@install',
- 'as' => 'slack-install',
- ]);
-});
\ No newline at end of file
+ $router->get('slack-install', [
+ 'uses' => 'SlackAppController@install',
+ 'as' => 'slack-install',
+ ]);
+
+ $router->get('', [
+ 'uses' => 'SlackAppController@home',
+ 'as' => 'home',
+ ]);
+ });
+
+app('router')
+ ->group(array_merge($routeConfig,['prefix'=>'api']), function ($router) {
+ $router->post('event', [
+ 'uses' => 'EventsController@fire',
+ 'as' => 'event',
+ ]);
+ });
\ No newline at end of file