diff --git a/app/Http/Controllers/Admin/AdminInstanceController.php b/app/Http/Controllers/Admin/AdminInstanceController.php
index b24592c31..6a17fdb2a 100644
--- a/app/Http/Controllers/Admin/AdminInstanceController.php
+++ b/app/Http/Controllers/Admin/AdminInstanceController.php
@@ -8,66 +8,13 @@ use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Services\InstanceService;
+use App\Http\Resources\AdminInstance;
trait AdminInstanceController
{
-
public function instances(Request $request)
{
- $this->validate($request, [
-
- 'filter' => [
- 'nullable',
- 'string',
- 'min:1',
- 'max:20',
- Rule::in([
- 'cw',
- 'unlisted',
- 'banned',
- // 'popular',
- 'new',
- 'all'
- ])
- ],
- ]);
- if($request->has('q') && $request->filled('q')) {
- $instances = Instance::where('domain', 'like', '%' . $request->input('q') . '%')->simplePaginate(10);
- } else if($request->has('filter') && $request->filled('filter')) {
- switch ($request->filter) {
- case 'cw':
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->whereAutoCw(true)->orderByDesc('id')->simplePaginate(10);
- break;
- case 'unlisted':
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->whereUnlisted(true)->orderByDesc('id')->simplePaginate(10);
- break;
- case 'banned':
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->whereBanned(true)->orderByDesc('id')->simplePaginate(10);
- break;
- case 'new':
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->latest()->simplePaginate(10);
- break;
- // case 'popular':
- // $popular = Profile::selectRaw('*, count(domain) as count')
- // ->whereNotNull('domain')
- // ->groupBy('domain')
- // ->orderByDesc('count')
- // ->take(10)
- // ->get()
- // ->pluck('domain')
- // ->toArray();
- // $instances = Instance::whereIn('domain', $popular)->simplePaginate(10);
- // break;
-
- default:
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->orderByDesc('id')->simplePaginate(10);
- break;
- }
- } else {
- $instances = Instance::select('id', 'domain', 'unlisted', 'auto_cw', 'banned')->orderByDesc('id')->simplePaginate(10);
- }
-
- return view('admin.instances.home', compact('instances'));
+ return view('admin.instances.home');
}
public function instanceScan(Request $request)
@@ -133,4 +80,146 @@ trait AdminInstanceController
return response()->json([]);
}
+
+ public function getInstancesStatsApi(Request $request)
+ {
+ return InstanceService::stats();
+ }
+
+ public function getInstancesQueryApi(Request $request)
+ {
+ $this->validate($request, [
+ 'q' => 'required'
+ ]);
+
+ $q = $request->input('q');
+
+ return AdminInstance::collection(
+ Instance::where('domain', 'like', '%' . $q . '%')
+ ->orderByDesc('user_count')
+ ->cursorPaginate(20)
+ ->withQueryString()
+ );
+ }
+
+ public function getInstancesApi(Request $request)
+ {
+ $this->validate($request, [
+ 'filter' => [
+ 'nullable',
+ 'string',
+ 'min:1',
+ 'max:20',
+ Rule::in([
+ 'cw',
+ 'unlisted',
+ 'banned',
+ 'popular_users',
+ 'popular_statuses',
+ 'new',
+ 'all'
+ ])
+ ],
+ ]);
+ $filter = $request->input('filter');
+ $query = $request->input('q');
+
+ return AdminInstance::collection(Instance::when($query, function($q, $qq) use($query) {
+ return $q->where('domain', 'like', '%' . $query . '%');
+ })
+ ->when($filter, function($q, $f) use($filter) {
+ if($filter == 'cw') { return $q->whereAutoCw(true)->orderByDesc('id'); }
+ if($filter == 'unlisted') { return $q->whereUnlisted(true)->orderByDesc('id'); }
+ if($filter == 'banned') { return $q->whereBanned(true)->orderByDesc('id'); }
+ if($filter == 'new') { return $q->orderByDesc('id'); }
+ if($filter == 'popular_users') { return $q->orderByDesc('user_count'); }
+ if($filter == 'popular_statuses') { return $q->orderByDesc('status_count'); }
+ return $q->orderByDesc('id');
+ }, function($q) {
+ return $q->orderByDesc('id');
+ })
+ ->cursorPaginate(10)
+ ->withQueryString());
+ }
+
+ public function postInstanceUpdateApi(Request $request)
+ {
+ $this->validate($request, [
+ 'id' => 'required',
+ 'banned' => 'boolean',
+ 'auto_cw' => 'boolean',
+ 'unlisted' => 'boolean',
+ 'notes' => 'nullable|string|max:500',
+ ]);
+
+ $id = $request->input('id');
+ $instance = Instance::findOrFail($id);
+ $instance->update($request->only([
+ 'banned',
+ 'auto_cw',
+ 'unlisted',
+ 'notes'
+ ]));
+
+ InstanceService::refresh();
+
+ return new AdminInstance($instance);
+ }
+
+ public function postInstanceCreateNewApi(Request $request)
+ {
+ $this->validate($request, [
+ 'domain' => 'required|string',
+ 'banned' => 'boolean',
+ 'auto_cw' => 'boolean',
+ 'unlisted' => 'boolean',
+ 'notes' => 'nullable|string|max:500'
+ ]);
+
+ $domain = $request->input('domain');
+
+ abort_if(!strpos($domain, '.'), 400, 'Invalid domain');
+ abort_if(!filter_var($domain, FILTER_VALIDATE_DOMAIN), 400, 'Invalid domain');
+
+ $instance = new Instance;
+ $instance->domain = $request->input('domain');
+ $instance->banned = $request->input('banned');
+ $instance->auto_cw = $request->input('auto_cw');
+ $instance->unlisted = $request->input('unlisted');
+ $instance->manually_added = true;
+ $instance->notes = $request->input('notes');
+ $instance->save();
+
+ InstanceService::refresh();
+
+ return new AdminInstance($instance);
+ }
+
+ public function postInstanceRefreshStatsApi(Request $request)
+ {
+ $this->validate($request, [
+ 'id' => 'required'
+ ]);
+
+ $instance = Instance::findOrFail($request->input('id'));
+ $instance->user_count = Profile::whereDomain($instance->domain)->count();
+ $instance->status_count = Profile::whereDomain($instance->domain)->leftJoin('statuses', 'profiles.id', '=', 'statuses.profile_id')->count();
+ $instance->save();
+
+ return new AdminInstance($instance);
+ }
+
+ public function postInstanceDeleteApi(Request $request)
+ {
+ $this->validate($request, [
+ 'id' => 'required'
+ ]);
+
+ $instance = Instance::findOrFail($request->input('id'));
+ $instance->delete();
+
+ InstanceService::refresh();
+
+ return 200;
+ }
}
diff --git a/app/Http/Controllers/Api/BaseApiController.php b/app/Http/Controllers/Api/BaseApiController.php
index 9dd84aa0b..83828a9f3 100644
--- a/app/Http/Controllers/Api/BaseApiController.php
+++ b/app/Http/Controllers/Api/BaseApiController.php
@@ -96,89 +96,6 @@ class BaseApiController extends Controller
return response()->json($res);
}
- public function accounts(Request $request, $id)
- {
- abort_if(!$request->user(), 403);
- $profile = Profile::findOrFail($id);
- $resource = new Fractal\Resource\Item($profile, new AccountTransformer());
- $res = $this->fractal->createData($resource)->toArray();
-
- return response()->json($res);
- }
-
- public function accountFollowers(Request $request, $id)
- {
- abort_if(!$request->user(), 403);
- $profile = Profile::findOrFail($id);
- $followers = $profile->followers;
- $resource = new Fractal\Resource\Collection($followers, new AccountTransformer());
- $res = $this->fractal->createData($resource)->toArray();
-
- return response()->json($res);
- }
-
- public function accountFollowing(Request $request, $id)
- {
- abort_if(!$request->user(), 403);
- $profile = Profile::findOrFail($id);
- $following = $profile->following;
- $resource = new Fractal\Resource\Collection($following, new AccountTransformer());
- $res = $this->fractal->createData($resource)->toArray();
-
- return response()->json($res);
- }
-
- public function accountStatuses(Request $request, $id)
- {
- abort_if(!$request->user(), 403);
- $this->validate($request, [
- 'only_media' => 'nullable',
- 'pinned' => 'nullable',
- 'exclude_replies' => 'nullable',
- 'max_id' => 'nullable|integer|min:1',
- 'since_id' => 'nullable|integer|min:1',
- 'min_id' => 'nullable|integer|min:1',
- 'limit' => 'nullable|integer|min:1|max:24'
- ]);
- $limit = $request->limit ?? 20;
- $max_id = $request->max_id ?? false;
- $min_id = $request->min_id ?? false;
- $since_id = $request->since_id ?? false;
- $only_media = $request->only_media ?? false;
- $user = Auth::user();
- $account = Profile::whereNull('status')->findOrFail($id);
- $statuses = $account->statuses()->getQuery();
- if($only_media == true) {
- $statuses = $statuses
- ->whereIn('scope', ['public','unlisted'])
- ->whereHas('media')
- ->whereNull('in_reply_to_id')
- ->whereNull('reblog_of_id');
- }
- if($id == $account->id && !$max_id && !$min_id && !$since_id) {
- $statuses = $statuses->orderBy('id', 'desc')
- ->paginate($limit);
- } else if($since_id) {
- $statuses = $statuses->where('id', '>', $since_id)
- ->orderBy('id', 'DESC')
- ->paginate($limit);
- } else if($min_id) {
- $statuses = $statuses->where('id', '>', $min_id)
- ->orderBy('id', 'ASC')
- ->paginate($limit);
- } else if($max_id) {
- $statuses = $statuses->where('id', '<', $max_id)
- ->orderBy('id', 'DESC')
- ->paginate($limit);
- } else {
- $statuses = $statuses->whereScope('public')->orderBy('id', 'desc')->paginate($limit);
- }
- $resource = new Fractal\Resource\Collection($statuses, new StatusTransformer());
- $res = $this->fractal->createData($resource)->toArray();
-
- return response()->json($res);
- }
-
public function avatarUpdate(Request $request)
{
abort_if(!$request->user(), 403);
@@ -215,21 +132,6 @@ class BaseApiController extends Controller
]);
}
- public function showTempMedia(Request $request, $profileId, $mediaId, $timestamp)
- {
- abort(400, 'Endpoint deprecated');
- }
-
- public function uploadMedia(Request $request)
- {
- abort(400, 'Endpoint deprecated');
- }
-
- public function deleteMedia(Request $request)
- {
- abort(400, 'Endpoint deprecated');
- }
-
public function verifyCredentials(Request $request)
{
$user = $request->user();
@@ -242,21 +144,6 @@ class BaseApiController extends Controller
return response()->json($res);
}
- public function drafts(Request $request)
- {
- $user = $request->user();
- abort_if(!$request->user(), 403);
-
- $medias = Media::whereUserId($user->id)
- ->whereNull('status_id')
- ->latest()
- ->take(13)
- ->get();
- $resource = new Fractal\Resource\Collection($medias, new MediaDraftTransformer());
- $res = $this->fractal->createData($resource)->toArray();
- return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
- }
-
public function accountLikes(Request $request)
{
abort_if(!$request->user(), 403);
diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php
index 0e8313f1e..1cfc820a3 100644
--- a/app/Http/Controllers/ApiController.php
+++ b/app/Http/Controllers/ApiController.php
@@ -14,16 +14,9 @@ use Auth, Cache;
use Illuminate\Support\Facades\Redis;
use App\Util\Site\Config;
use Illuminate\Http\Request;
-use App\Services\SuggestionService;
class ApiController extends BaseApiController
{
- // todo: deprecate and remove
- public function hydrateLikes(Request $request)
- {
- return response()->json([]);
- }
-
public function siteConfiguration(Request $request)
{
return response()->json(Config::get());
@@ -31,79 +24,6 @@ class ApiController extends BaseApiController
public function userRecommendations(Request $request)
{
- abort_if(!Auth::check(), 403);
- abort_if(!config('exp.rec'), 400);
-
- $id = Auth::user()->profile->id;
-
- $following = Cache::remember('profile:following:'.$id, now()->addHours(12), function() use ($id) {
- return Follower::whereProfileId($id)->pluck('following_id')->toArray();
- });
- array_push($following, $id);
- $ids = SuggestionService::get();
- $filters = UserFilter::whereUserId($id)
- ->whereFilterableType('App\Profile')
- ->whereIn('filter_type', ['mute', 'block'])
- ->pluck('filterable_id')->toArray();
- $following = array_merge($following, $filters);
-
- $key = config('cache.prefix').':api:local:exp:rec:'.$id;
- $ttl = (int) Redis::ttl($key);
-
- if($request->filled('refresh') == true && (290 > $ttl) == true) {
- Cache::forget('api:local:exp:rec:'.$id);
- }
-
- $res = Cache::remember('api:local:exp:rec:'.$id, now()->addMinutes(5), function() use($id, $following, $ids) {
- return Profile::select(
- 'id',
- 'username'
- )
- ->whereNotIn('id', $following)
- ->whereIn('id', $ids)
- ->whereIsPrivate(0)
- ->whereNull('status')
- ->whereNull('domain')
- ->inRandomOrder()
- ->take(3)
- ->get()
- ->map(function($item, $key) {
- return [
- 'id' => $item->id,
- 'avatar' => $item->avatarUrl(),
- 'username' => $item->username,
- 'message' => 'Recommended for You'
- ];
- });
- });
-
- return response()->json($res->all());
+ return response()->json([]);
}
-
- public function composeLocationSearch(Request $request)
- {
- abort_if(!Auth::check(), 403);
- $this->validate($request, [
- 'q' => 'required|string|max:100'
- ]);
- $q = filter_var($request->input('q'), FILTER_SANITIZE_STRING);
- $hash = hash('sha256', $q);
- $key = 'search:location:id:' . $hash;
- $places = Cache::remember($key, now()->addMinutes(15), function() use($q) {
- $q = '%' . $q . '%';
- return Place::where('name', 'like', $q)
- ->take(80)
- ->get()
- ->map(function($r) {
- return [
- 'id' => $r->id,
- 'name' => $r->name,
- 'country' => $r->country,
- 'url' => $r->url()
- ];
- });
- });
- return $places;
- }
-
}
diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php
index 3f6795d5b..d092d349b 100644
--- a/app/Http/Controllers/ProfileController.php
+++ b/app/Http/Controllers/ProfileController.php
@@ -207,7 +207,7 @@ class ProfileController extends Controller
abort_if(!$profile || $profile['locked'] || !$profile['local'], 404);
- $data = Cache::remember('pf:atom:user-feed:by-id:' . $profile['id'], 86400, function() use($pid, $profile) {
+ $data = Cache::remember('pf:atom:user-feed:by-id:' . $profile['id'], 43200, function() use($pid, $profile) {
$items = DB::table('statuses')
->whereProfileId($pid)
->whereVisibility('public')
diff --git a/app/Http/Resources/AdminInstance.php b/app/Http/Resources/AdminInstance.php
index 4a52e3481..d534f4681 100644
--- a/app/Http/Resources/AdminInstance.php
+++ b/app/Http/Resources/AdminInstance.php
@@ -24,6 +24,9 @@ class AdminInstance extends JsonResource
'user_count' => $this->user_count,
'status_count' => $this->status_count,
'last_crawled_at' => $this->last_crawled_at,
+ 'notes' => $this->notes,
+ 'base_domain' => $this->base_domain,
+ 'ban_subdomains' => $this->ban_subdomains,
'actors_last_synced_at' => $this->actors_last_synced_at,
'created_at' => $this->created_at,
];
diff --git a/app/Instance.php b/app/Instance.php
index 5541d86c9..6a7b8e6f2 100644
--- a/app/Instance.php
+++ b/app/Instance.php
@@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
class Instance extends Model
{
- protected $fillable = ['domain'];
+ protected $fillable = ['domain', 'banned', 'auto_cw', 'unlisted', 'notes'];
public function profiles()
{
diff --git a/app/Jobs/InboxPipeline/DeleteWorker.php b/app/Jobs/InboxPipeline/DeleteWorker.php
index 05d0138e3..03a20bdd5 100644
--- a/app/Jobs/InboxPipeline/DeleteWorker.php
+++ b/app/Jobs/InboxPipeline/DeleteWorker.php
@@ -126,6 +126,11 @@ class DeleteWorker implements ShouldQueue
return false;
}
$signatureData = HttpSignature::parseSignatureHeader($signature);
+
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return false;
+ }
+
$keyId = Helpers::validateUrl($signatureData['keyId']);
$id = Helpers::validateUrl($bodyDecoded['id']);
$keyDomain = parse_url($keyId, PHP_URL_HOST);
@@ -186,6 +191,11 @@ class DeleteWorker implements ShouldQueue
return;
}
$signatureData = HttpSignature::parseSignatureHeader($signature);
+
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return;
+ }
+
$keyId = Helpers::validateUrl($signatureData['keyId']);
$actor = Profile::whereKeyId($keyId)->whereNotNull('remote_url')->first();
if(!$actor) {
diff --git a/app/Jobs/InboxPipeline/InboxValidator.php b/app/Jobs/InboxPipeline/InboxValidator.php
index 8b4d018a4..4017d3acd 100644
--- a/app/Jobs/InboxPipeline/InboxValidator.php
+++ b/app/Jobs/InboxPipeline/InboxValidator.php
@@ -5,9 +5,9 @@ namespace App\Jobs\InboxPipeline;
use Cache;
use App\Profile;
use App\Util\ActivityPub\{
- Helpers,
- HttpSignature,
- Inbox
+ Helpers,
+ HttpSignature,
+ Inbox
};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -21,189 +21,199 @@ use Illuminate\Support\Lottery;
class InboxValidator implements ShouldQueue
{
- use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
- protected $username;
- protected $headers;
- protected $payload;
+ protected $username;
+ protected $headers;
+ protected $payload;
- public $timeout = 300;
- public $tries = 1;
- public $maxExceptions = 1;
+ public $timeout = 300;
+ public $tries = 1;
+ public $maxExceptions = 1;
- /**
- * Create a new job instance.
- *
- * @return void
- */
- public function __construct($username, $headers, $payload)
- {
- $this->username = $username;
- $this->headers = $headers;
- $this->payload = $payload;
- }
+ /**
+ * Create a new job instance.
+ *
+ * @return void
+ */
+ public function __construct($username, $headers, $payload)
+ {
+ $this->username = $username;
+ $this->headers = $headers;
+ $this->payload = $payload;
+ }
- /**
- * Execute the job.
- *
- * @return void
- */
- public function handle()
- {
- $username = $this->username;
- $headers = $this->headers;
+ /**
+ * Execute the job.
+ *
+ * @return void
+ */
+ public function handle()
+ {
+ $username = $this->username;
+ $headers = $this->headers;
- if(empty($headers) || empty($this->payload) || !isset($headers['signature']) || !isset($headers['date'])) {
- return;
- }
+ if(empty($headers) || empty($this->payload) || !isset($headers['signature']) || !isset($headers['date'])) {
+ return;
+ }
- $payload = json_decode($this->payload, true, 8);
+ $payload = json_decode($this->payload, true, 8);
- if(isset($payload['id'])) {
- $lockKey = 'pf:ap:user-inbox:activity:' . hash('sha256', $payload['id']);
- if(Cache::get($lockKey) !== null) {
- // Job processed already
- return 1;
- }
- Cache::put($lockKey, 1, 3600);
- }
+ if(isset($payload['id'])) {
+ $lockKey = 'pf:ap:user-inbox:activity:' . hash('sha256', $payload['id']);
+ if(Cache::get($lockKey) !== null) {
+ // Job processed already
+ return 1;
+ }
+ Cache::put($lockKey, 1, 3600);
+ }
- $profile = Profile::whereNull('domain')->whereUsername($username)->first();
+ $profile = Profile::whereNull('domain')->whereUsername($username)->first();
- if(empty($profile) || empty($headers) || empty($payload)) {
- return;
- }
+ if(empty($profile) || empty($headers) || empty($payload)) {
+ return;
+ }
- if($profile->status != null) {
- return;
- }
+ if($profile->status != null) {
+ return;
+ }
- if($this->verifySignature($headers, $profile, $payload) == true) {
- if(isset($payload['type']) && in_array($payload['type'], ['Follow', 'Accept']) ) {
- ActivityHandler::dispatch($headers, $profile, $payload)->onQueue('follow');
- } else {
- $onQueue = Lottery::odds(1, 12)->winner(fn () => 'high')->loser(fn () => 'inbox')->choose();
- ActivityHandler::dispatch($headers, $profile, $payload)->onQueue($onQueue);
- }
- return;
- } else {
- return;
- }
+ if($this->verifySignature($headers, $profile, $payload) == true) {
+ if(isset($payload['type']) && in_array($payload['type'], ['Follow', 'Accept']) ) {
+ ActivityHandler::dispatch($headers, $profile, $payload)->onQueue('follow');
+ } else {
+ $onQueue = Lottery::odds(1, 12)->winner(fn () => 'high')->loser(fn () => 'inbox')->choose();
+ ActivityHandler::dispatch($headers, $profile, $payload)->onQueue($onQueue);
+ }
+ return;
+ } else {
+ return;
+ }
- }
+ }
- protected function verifySignature($headers, $profile, $payload)
- {
- $body = $this->payload;
- $bodyDecoded = $payload;
- $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
- $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
- if(!$signature) {
- return false;
- }
- if(!$date) {
- return false;
- }
- if(!now()->parse($date)->gt(now()->subDays(1)) ||
- !now()->parse($date)->lt(now()->addDays(1))
- ) {
- return false;
- }
- if(!isset($bodyDecoded['id'])) {
- return false;
- }
- $signatureData = HttpSignature::parseSignatureHeader($signature);
- $keyId = Helpers::validateUrl($signatureData['keyId']);
- $id = Helpers::validateUrl($bodyDecoded['id']);
- $keyDomain = parse_url($keyId, PHP_URL_HOST);
- $idDomain = parse_url($id, PHP_URL_HOST);
- if(isset($bodyDecoded['object'])
- && is_array($bodyDecoded['object'])
- && isset($bodyDecoded['object']['attributedTo'])
- ) {
- $attr = Helpers::pluckval($bodyDecoded['object']['attributedTo']);
- if(is_array($attr)) {
- if(isset($attr['id'])) {
- $attr = $attr['id'];
- } else {
- $attr = "";
- }
- }
- if(parse_url($attr, PHP_URL_HOST) !== $keyDomain) {
- return false;
- }
- }
- if(!$keyDomain || !$idDomain || $keyDomain !== $idDomain) {
- return false;
- }
- $actor = Profile::whereKeyId($keyId)->first();
- if(!$actor) {
- $actorUrl = Helpers::pluckval($bodyDecoded['actor']);
- $actor = Helpers::profileFirstOrNew($actorUrl);
- }
- if(!$actor) {
- return false;
- }
- $pkey = openssl_pkey_get_public($actor->public_key);
- if(!$pkey) {
- return false;
- }
- $inboxPath = "/users/{$profile->username}/inbox";
- list($verified, $headers) = HttpSignature::verify($pkey, $signatureData, $headers, $inboxPath, $body);
- if($verified == 1) {
- return true;
- } else {
- return false;
- }
- }
+ protected function verifySignature($headers, $profile, $payload)
+ {
+ $body = $this->payload;
+ $bodyDecoded = $payload;
+ $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
+ $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
+ if(!$signature) {
+ return false;
+ }
+ if(!$date) {
+ return false;
+ }
+ if(!now()->parse($date)->gt(now()->subDays(1)) ||
+ !now()->parse($date)->lt(now()->addDays(1))
+ ) {
+ return false;
+ }
+ if(!isset($bodyDecoded['id'])) {
+ return false;
+ }
+ $signatureData = HttpSignature::parseSignatureHeader($signature);
- protected function blindKeyRotation($headers, $profile, $payload)
- {
- $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
- $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
- if(!$signature) {
- return;
- }
- if(!$date) {
- return;
- }
- if(!now()->parse($date)->gt(now()->subDays(1)) ||
- !now()->parse($date)->lt(now()->addDays(1))
- ) {
- return;
- }
- $signatureData = HttpSignature::parseSignatureHeader($signature);
- $keyId = Helpers::validateUrl($signatureData['keyId']);
- $actor = Profile::whereKeyId($keyId)->whereNotNull('remote_url')->first();
- if(!$actor) {
- return;
- }
- if(Helpers::validateUrl($actor->remote_url) == false) {
- return;
- }
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return false;
+ }
- try {
- $res = Http::timeout(20)->withHeaders([
- 'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
- 'User-Agent' => 'PixelfedBot v0.1 - https://pixelfed.org',
- ])->get($actor->remote_url);
- } catch (ConnectionException $e) {
- return false;
- }
+ $keyId = Helpers::validateUrl($signatureData['keyId']);
+ $id = Helpers::validateUrl($bodyDecoded['id']);
+ $keyDomain = parse_url($keyId, PHP_URL_HOST);
+ $idDomain = parse_url($id, PHP_URL_HOST);
+ if(isset($bodyDecoded['object'])
+ && is_array($bodyDecoded['object'])
+ && isset($bodyDecoded['object']['attributedTo'])
+ ) {
+ $attr = Helpers::pluckval($bodyDecoded['object']['attributedTo']);
+ if(is_array($attr)) {
+ if(isset($attr['id'])) {
+ $attr = $attr['id'];
+ } else {
+ $attr = "";
+ }
+ }
+ if(parse_url($attr, PHP_URL_HOST) !== $keyDomain) {
+ return false;
+ }
+ }
+ if(!$keyDomain || !$idDomain || $keyDomain !== $idDomain) {
+ return false;
+ }
+ $actor = Profile::whereKeyId($keyId)->first();
+ if(!$actor) {
+ $actorUrl = Helpers::pluckval($bodyDecoded['actor']);
+ $actor = Helpers::profileFirstOrNew($actorUrl);
+ }
+ if(!$actor) {
+ return false;
+ }
+ $pkey = openssl_pkey_get_public($actor->public_key);
+ if(!$pkey) {
+ return false;
+ }
+ $inboxPath = "/users/{$profile->username}/inbox";
+ list($verified, $headers) = HttpSignature::verify($pkey, $signatureData, $headers, $inboxPath, $body);
+ if($verified == 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
- if(!$res->ok()) {
- return false;
- }
+ protected function blindKeyRotation($headers, $profile, $payload)
+ {
+ $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
+ $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
+ if(!$signature) {
+ return;
+ }
+ if(!$date) {
+ return;
+ }
+ if(!now()->parse($date)->gt(now()->subDays(1)) ||
+ !now()->parse($date)->lt(now()->addDays(1))
+ ) {
+ return;
+ }
+ $signatureData = HttpSignature::parseSignatureHeader($signature);
- $res = json_decode($res->body(), true, 8);
- if(!$res || empty($res) || !isset($res['publicKey']) || !isset($res['publicKey']['id'])) {
- return;
- }
- if($res['publicKey']['id'] !== $actor->key_id) {
- return;
- }
- $actor->public_key = $res['publicKey']['publicKeyPem'];
- $actor->save();
- return $this->verifySignature($headers, $profile, $payload);
- }
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return;
+ }
+
+ $keyId = Helpers::validateUrl($signatureData['keyId']);
+ $actor = Profile::whereKeyId($keyId)->whereNotNull('remote_url')->first();
+ if(!$actor) {
+ return;
+ }
+ if(Helpers::validateUrl($actor->remote_url) == false) {
+ return;
+ }
+
+ try {
+ $res = Http::timeout(20)->withHeaders([
+ 'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
+ 'User-Agent' => 'PixelfedBot v0.1 - https://pixelfed.org',
+ ])->get($actor->remote_url);
+ } catch (ConnectionException $e) {
+ return false;
+ }
+
+ if(!$res->ok()) {
+ return false;
+ }
+
+ $res = json_decode($res->body(), true, 8);
+ if(!$res || empty($res) || !isset($res['publicKey']) || !isset($res['publicKey']['id'])) {
+ return;
+ }
+ if($res['publicKey']['id'] !== $actor->key_id) {
+ return;
+ }
+ $actor->public_key = $res['publicKey']['publicKeyPem'];
+ $actor->save();
+ return $this->verifySignature($headers, $profile, $payload);
+ }
}
diff --git a/app/Jobs/InboxPipeline/InboxWorker.php b/app/Jobs/InboxPipeline/InboxWorker.php
index 305430085..c8508c0fc 100644
--- a/app/Jobs/InboxPipeline/InboxWorker.php
+++ b/app/Jobs/InboxPipeline/InboxWorker.php
@@ -5,9 +5,9 @@ namespace App\Jobs\InboxPipeline;
use Cache;
use App\Profile;
use App\Util\ActivityPub\{
- Helpers,
- HttpSignature,
- Inbox
+ Helpers,
+ HttpSignature,
+ Inbox
};
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -20,171 +20,180 @@ use Illuminate\Http\Client\ConnectionException;
class InboxWorker implements ShouldQueue
{
- use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
- protected $headers;
- protected $payload;
+ protected $headers;
+ protected $payload;
- public $timeout = 300;
- public $tries = 1;
- public $maxExceptions = 1;
+ public $timeout = 300;
+ public $tries = 1;
+ public $maxExceptions = 1;
- /**
- * Create a new job instance.
- *
- * @return void
- */
- public function __construct($headers, $payload)
- {
- $this->headers = $headers;
- $this->payload = $payload;
- }
+ /**
+ * Create a new job instance.
+ *
+ * @return void
+ */
+ public function __construct($headers, $payload)
+ {
+ $this->headers = $headers;
+ $this->payload = $payload;
+ }
- /**
- * Execute the job.
- *
- * @return void
- */
- public function handle()
- {
- $profile = null;
- $headers = $this->headers;
+ /**
+ * Execute the job.
+ *
+ * @return void
+ */
+ public function handle()
+ {
+ $profile = null;
+ $headers = $this->headers;
- if(empty($headers) || empty($this->payload) || !isset($headers['signature']) || !isset($headers['date'])) {
- return;
- }
+ if(empty($headers) || empty($this->payload) || !isset($headers['signature']) || !isset($headers['date'])) {
+ return;
+ }
- $payload = json_decode($this->payload, true, 8);
+ $payload = json_decode($this->payload, true, 8);
- if(isset($payload['id'])) {
- $lockKey = 'pf:ap:user-inbox:activity:' . hash('sha256', $payload['id']);
- if(Cache::get($lockKey) !== null) {
- // Job processed already
- return 1;
- }
- Cache::put($lockKey, 1, 3600);
- }
+ if(isset($payload['id'])) {
+ $lockKey = 'pf:ap:user-inbox:activity:' . hash('sha256', $payload['id']);
+ if(Cache::get($lockKey) !== null) {
+ // Job processed already
+ return 1;
+ }
+ Cache::put($lockKey, 1, 3600);
+ }
- if($this->verifySignature($headers, $payload) == true) {
- ActivityHandler::dispatch($headers, $profile, $payload)->onQueue('shared');
- return;
- } else {
- return;
- }
- }
+ if($this->verifySignature($headers, $payload) == true) {
+ ActivityHandler::dispatch($headers, $profile, $payload)->onQueue('shared');
+ return;
+ } else {
+ return;
+ }
+ }
- protected function verifySignature($headers, $payload)
- {
- $body = $this->payload;
- $bodyDecoded = $payload;
- $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
- $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
- if(!$signature) {
- return false;
- }
- if(!$date) {
- return false;
- }
- if(!now()->parse($date)->gt(now()->subDays(1)) ||
- !now()->parse($date)->lt(now()->addDays(1))
- ) {
- return false;
- }
- if(!isset($bodyDecoded['id'])) {
- return false;
- }
- $signatureData = HttpSignature::parseSignatureHeader($signature);
- $keyId = Helpers::validateUrl($signatureData['keyId']);
- $id = Helpers::validateUrl($bodyDecoded['id']);
- $keyDomain = parse_url($keyId, PHP_URL_HOST);
- $idDomain = parse_url($id, PHP_URL_HOST);
- if(isset($bodyDecoded['object'])
- && is_array($bodyDecoded['object'])
- && isset($bodyDecoded['object']['attributedTo'])
- ) {
- $attr = Helpers::pluckval($bodyDecoded['object']['attributedTo']);
- if(is_array($attr)) {
- if(isset($attr['id'])) {
- $attr = $attr['id'];
- } else {
- $attr = "";
- }
- }
- if(parse_url($attr, PHP_URL_HOST) !== $keyDomain) {
- return false;
- }
- }
- if(!$keyDomain || !$idDomain || $keyDomain !== $idDomain) {
- return false;
- }
- $actor = Profile::whereKeyId($keyId)->first();
- if(!$actor) {
- $actorUrl = Helpers::pluckval($bodyDecoded['actor']);
- $actor = Helpers::profileFirstOrNew($actorUrl);
- }
- if(!$actor) {
- return false;
- }
- $pkey = openssl_pkey_get_public($actor->public_key);
- if(!$pkey) {
- return false;
- }
- $inboxPath = "/f/inbox";
- list($verified, $headers) = HttpSignature::verify($pkey, $signatureData, $headers, $inboxPath, $body);
- if($verified == 1) {
- return true;
- } else {
- return false;
- }
- }
+ protected function verifySignature($headers, $payload)
+ {
+ $body = $this->payload;
+ $bodyDecoded = $payload;
+ $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
+ $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
+ if(!$signature) {
+ return false;
+ }
+ if(!$date) {
+ return false;
+ }
+ if(!now()->parse($date)->gt(now()->subDays(1)) ||
+ !now()->parse($date)->lt(now()->addDays(1))
+ ) {
+ return false;
+ }
+ if(!isset($bodyDecoded['id'])) {
+ return false;
+ }
+ $signatureData = HttpSignature::parseSignatureHeader($signature);
- protected function blindKeyRotation($headers, $payload)
- {
- $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
- $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
- if(!$signature) {
- return;
- }
- if(!$date) {
- return;
- }
- if(!now()->parse($date)->gt(now()->subDays(1)) ||
- !now()->parse($date)->lt(now()->addDays(1))
- ) {
- return;
- }
- $signatureData = HttpSignature::parseSignatureHeader($signature);
- $keyId = Helpers::validateUrl($signatureData['keyId']);
- $actor = Profile::whereKeyId($keyId)->whereNotNull('remote_url')->first();
- if(!$actor) {
- return;
- }
- if(Helpers::validateUrl($actor->remote_url) == false) {
- return;
- }
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return false;
+ }
- try {
- $res = Http::timeout(20)->withHeaders([
- 'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
- 'User-Agent' => 'PixelfedBot v0.1 - https://pixelfed.org',
- ])->get($actor->remote_url);
- } catch (ConnectionException $e) {
- return false;
- }
+ $keyId = Helpers::validateUrl($signatureData['keyId']);
+ $id = Helpers::validateUrl($bodyDecoded['id']);
+ $keyDomain = parse_url($keyId, PHP_URL_HOST);
+ $idDomain = parse_url($id, PHP_URL_HOST);
+ if(isset($bodyDecoded['object'])
+ && is_array($bodyDecoded['object'])
+ && isset($bodyDecoded['object']['attributedTo'])
+ ) {
+ $attr = Helpers::pluckval($bodyDecoded['object']['attributedTo']);
+ if(is_array($attr)) {
+ if(isset($attr['id'])) {
+ $attr = $attr['id'];
+ } else {
+ $attr = "";
+ }
+ }
+ if(parse_url($attr, PHP_URL_HOST) !== $keyDomain) {
+ return false;
+ }
+ }
+ if(!$keyDomain || !$idDomain || $keyDomain !== $idDomain) {
+ return false;
+ }
+ $actor = Profile::whereKeyId($keyId)->first();
+ if(!$actor) {
+ $actorUrl = Helpers::pluckval($bodyDecoded['actor']);
+ $actor = Helpers::profileFirstOrNew($actorUrl);
+ }
+ if(!$actor) {
+ return false;
+ }
+ $pkey = openssl_pkey_get_public($actor->public_key);
+ if(!$pkey) {
+ return false;
+ }
+ $inboxPath = "/f/inbox";
+ list($verified, $headers) = HttpSignature::verify($pkey, $signatureData, $headers, $inboxPath, $body);
+ if($verified == 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
- if(!$res->ok()) {
- return false;
- }
+ protected function blindKeyRotation($headers, $payload)
+ {
+ $signature = is_array($headers['signature']) ? $headers['signature'][0] : $headers['signature'];
+ $date = is_array($headers['date']) ? $headers['date'][0] : $headers['date'];
+ if(!$signature) {
+ return;
+ }
+ if(!$date) {
+ return;
+ }
+ if(!now()->parse($date)->gt(now()->subDays(1)) ||
+ !now()->parse($date)->lt(now()->addDays(1))
+ ) {
+ return;
+ }
+ $signatureData = HttpSignature::parseSignatureHeader($signature);
+ if(!isset($signatureData['keyId'], $signatureData['signature'], $signatureData['headers']) || isset($signatureData['error'])) {
+ return;
+ }
- $res = json_decode($res->body(), true, 8);
- if(!$res || empty($res) || !isset($res['publicKey']) || !isset($res['publicKey']['id'])) {
- return;
- }
- if($res['publicKey']['id'] !== $actor->key_id) {
- return;
- }
- $actor->public_key = $res['publicKey']['publicKeyPem'];
- $actor->save();
- return $this->verifySignature($headers, $payload);
- }
+ $keyId = Helpers::validateUrl($signatureData['keyId']);
+ $actor = Profile::whereKeyId($keyId)->whereNotNull('remote_url')->first();
+ if(!$actor) {
+ return;
+ }
+ if(Helpers::validateUrl($actor->remote_url) == false) {
+ return;
+ }
+
+ try {
+ $res = Http::timeout(20)->withHeaders([
+ 'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
+ 'User-Agent' => 'PixelfedBot v0.1 - https://pixelfed.org',
+ ])->get($actor->remote_url);
+ } catch (ConnectionException $e) {
+ return false;
+ }
+
+ if(!$res->ok()) {
+ return false;
+ }
+
+ $res = json_decode($res->body(), true, 8);
+ if(!$res || empty($res) || !isset($res['publicKey']) || !isset($res['publicKey']['id'])) {
+ return;
+ }
+ if($res['publicKey']['id'] !== $actor->key_id) {
+ return;
+ }
+ $actor->public_key = $res['publicKey']['publicKeyPem'];
+ $actor->save();
+ return $this->verifySignature($headers, $payload);
+ }
}
diff --git a/app/Jobs/StatusPipeline/StatusDelete.php b/app/Jobs/StatusPipeline/StatusDelete.php
index d7f237e20..0a0721648 100644
--- a/app/Jobs/StatusPipeline/StatusDelete.php
+++ b/app/Jobs/StatusPipeline/StatusDelete.php
@@ -2,7 +2,7 @@
namespace App\Jobs\StatusPipeline;
-use DB, Storage;
+use DB, Cache, Storage;
use App\{
AccountInterstitial,
Bookmark,
@@ -81,6 +81,8 @@ class StatusDelete implements ShouldQueue
}
}
+ Cache::forget('pf:atom:user-feed:by-id:' . $status->profile_id);
+
if(config_cache('federation.activitypub.enabled') == true) {
return $this->fanoutDelete($status);
} else {
diff --git a/app/Jobs/StatusPipeline/StatusEntityLexer.php b/app/Jobs/StatusPipeline/StatusEntityLexer.php
index 591a06604..1ee57c559 100644
--- a/app/Jobs/StatusPipeline/StatusEntityLexer.php
+++ b/app/Jobs/StatusPipeline/StatusEntityLexer.php
@@ -12,6 +12,7 @@ use App\Services\PublicTimelineService;
use App\Util\Lexer\Autolink;
use App\Util\Lexer\Extractor;
use App\Util\Sentiment\Bouncer;
+use Cache;
use DB;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -166,6 +167,8 @@ class StatusEntityLexer implements ShouldQueue
if(config_cache('pixelfed.bouncer.enabled')) {
Bouncer::get($status);
}
+
+ Cache::forget('pf:atom:user-feed:by-id:' . $status->profile_id);
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
if( $status->uri == null &&
$status->scope == 'public' &&
diff --git a/app/Services/InstanceService.php b/app/Services/InstanceService.php
index b53e8ac00..f044f1b27 100644
--- a/app/Services/InstanceService.php
+++ b/app/Services/InstanceService.php
@@ -11,6 +11,7 @@ class InstanceService
const CACHE_KEY_BANNED_DOMAINS = 'instances:banned:domains';
const CACHE_KEY_UNLISTED_DOMAINS = 'instances:unlisted:domains';
const CACHE_KEY_NSFW_DOMAINS = 'instances:auto_cw:domains';
+ const CACHE_KEY_STATS = 'pf:services:instances:stats';
public static function getByDomain($domain)
{
@@ -52,11 +53,24 @@ class InstanceService
});
}
+ public static function stats()
+ {
+ return Cache::remember(self::CACHE_KEY_STATS, 86400, function() {
+ return [
+ 'total_count' => Instance::count(),
+ 'new_count' => Instance::where('created_at', '>', now()->subDays(14))->count(),
+ 'banned_count' => Instance::whereBanned(true)->count(),
+ 'nsfw_count' => Instance::whereAutoCw(true)->count()
+ ];
+ });
+ }
+
public static function refresh()
{
Cache::forget(self::CACHE_KEY_BANNED_DOMAINS);
Cache::forget(self::CACHE_KEY_UNLISTED_DOMAINS);
Cache::forget(self::CACHE_KEY_NSFW_DOMAINS);
+ Cache::forget(self::CACHE_KEY_STATS);
self::getBannedDomains();
self::getUnlistedDomains();
diff --git a/database/migrations/2023_03_19_050342_add_notes_to_instances_table.php b/database/migrations/2023_03_19_050342_add_notes_to_instances_table.php
new file mode 100644
index 000000000..b259c2e5f
--- /dev/null
+++ b/database/migrations/2023_03_19_050342_add_notes_to_instances_table.php
@@ -0,0 +1,48 @@
+text('notes')->nullable();
+ $table->boolean('manually_added')->default(false);
+ $table->string('base_domain')->nullable();
+ $table->boolean('ban_subdomains')->nullable()->index();
+ $table->string('ip_address')->nullable();
+ $table->boolean('list_limitation')->default(false)->index();
+ $table->index('banned');
+ $table->index('auto_cw');
+ $table->index('unlisted');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('instances', function (Blueprint $table) {
+ $table->dropColumn('notes');
+ $table->dropColumn('manually_added');
+ $table->dropColumn('base_domain');
+ $table->dropColumn('ban_subdomains');
+ $table->dropColumn('ip_address');
+ $table->dropColumn('list_limitation');
+ $table->dropIndex('instances_banned_index');
+ $table->dropIndex('instances_auto_cw_index');
+ $table->dropIndex('instances_unlisted_index');
+ });
+ }
+};
diff --git a/public/js/admin.js b/public/js/admin.js
index 2940baed0..f2cd2496c 100644
Binary files a/public/js/admin.js and b/public/js/admin.js differ
diff --git a/public/mix-manifest.json b/public/mix-manifest.json
index ff5a5e187..bc1ce547d 100644
Binary files a/public/mix-manifest.json and b/public/mix-manifest.json differ
diff --git a/resources/assets/components/admin/AdminInstances.vue b/resources/assets/components/admin/AdminInstances.vue
new file mode 100644
index 000000000..67bfe9fe6
--- /dev/null
+++ b/resources/assets/components/admin/AdminInstances.vue
@@ -0,0 +1,628 @@
+
+ Instances {{editingInstance.notes ? editingInstance.notes.length : 0}}/500 Enter a valid domain without https:// {{addNewInstance.notes ? addNewInstance.notes.length : 0}}/500Total Instances
+ {{ prettyCount(stats.total_count) }}
+ New (past 14 days)
+ {{ prettyCount(stats.new_count) }}
+ Banned Instances
+ {{ prettyCount(stats.banned_count) }}
+ NSFW Instances
+ {{ prettyCount(stats.nsfw_count) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Created
+
+
+
+
+
+ {{ instance.id }}
+
+
+ {{ instance.domain }}
+ {{ instance.software }}
+ {{ prettyCount(instance.user_count) }}
+ {{ prettyCount(instance.status_count) }}
+
+
+
+ {{ timeAgo(instance.created_at) }}
+
Warning
-No instances were found.
-Do you want to scan and populate instances from Profiles and Statuses?
--
- - @else -- {{$instance->domain}} -
-- @if($instance->unlisted) - - @endif - @if($instance->auto_cw) - - @endif - @if($instance->banned) - - @endif - Overview - -
-No results found
- - @endif - @if(request()->filled('filter') && $instances->count() == 0) -No results found
- - @endif -{{ $item['content'] }}
+ +{!! $item['content'] !!}
]]>+ A Creative Commons license is one of several public copyright licenses that enable the free distribution of an otherwise copyrighted "work". +
++ A CC license is used when an author wants to give other people the right to share, use, and build upon a work that the author has created. +
+ +For more information, please visit creativecommons.org
+@endsection diff --git a/routes/web.php b/routes/web.php index 8d028b745..f83a75788 100644 --- a/routes/web.php +++ b/routes/web.php @@ -113,6 +113,13 @@ Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->group(functio Route::get('hashtags/get', 'AdminController@hashtagsGet'); Route::post('hashtags/update', 'AdminController@hashtagsUpdate'); Route::post('hashtags/clear-trending-cache', 'AdminController@hashtagsClearTrendingCache'); + Route::get('instances/get', 'AdminController@getInstancesApi'); + Route::get('instances/stats', 'AdminController@getInstancesStatsApi'); + Route::get('instances/query', 'AdminController@getInstancesQueryApi'); + Route::post('instances/update', 'AdminController@postInstanceUpdateApi'); + Route::post('instances/create', 'AdminController@postInstanceCreateNewApi'); + Route::post('instances/delete', 'AdminController@postInstanceDeleteApi'); + Route::post('instances/refresh-stats', 'AdminController@postInstanceRefreshStatsApi'); }); }); @@ -211,9 +218,6 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('accounts/{id}', 'PublicApiController@account'); Route::post('avatar/update', 'ApiController@avatarUpdate'); Route::get('custom_emojis', 'Api\ApiV1Controller@customEmojis'); - Route::get('likes', 'ApiController@hydrateLikes'); - Route::post('media', 'ApiController@uploadMedia'); - Route::delete('media', 'ApiController@deleteMedia'); Route::get('notifications', 'ApiController@notifications'); Route::get('timelines/public', 'PublicApiController@publicTimelineApi'); Route::get('timelines/home', 'PublicApiController@homeTimelineApi'); @@ -277,7 +281,6 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::post('collection/{id}/publish', 'CollectionController@publish'); Route::get('profile/collections/{id}', 'CollectionController@getUserCollections'); - Route::get('compose/location/search', 'ApiController@composeLocationSearch'); Route::post('compose/tag/untagme', 'MediaTagController@untagProfile'); }); @@ -340,8 +343,6 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('auth/checkpoint', 'AccountController@twoFactorCheckpoint'); Route::post('auth/checkpoint', 'AccountController@twoFactorVerify'); - Route::get('media/preview/{profileId}/{mediaId}/{timestamp}', 'ApiController@showTempMedia')->name('temp-media'); - Route::get('results', 'SearchController@results'); Route::post('visibility', 'StatusController@toggleVisibility'); @@ -421,8 +422,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::delete('avatar', 'AvatarController@deleteAvatar'); Route::get('password', 'SettingsController@password')->name('settings.password')->middleware('dangerzone'); Route::post('password', 'SettingsController@passwordUpdate')->middleware('dangerzone'); - Route::get('email', 'SettingsController@email')->name('settings.email'); - Route::post('email', 'SettingsController@emailUpdate'); + Route::get('email', 'SettingsController@email')->name('settings.email')->middleware('dangerzone'); + Route::post('email', 'SettingsController@emailUpdate')->middleware('dangerzone'); Route::get('notifications', 'SettingsController@notifications')->name('settings.notifications'); Route::get('privacy', 'SettingsController@privacy')->name('settings.privacy'); Route::post('privacy', 'SettingsController@privacyStore'); @@ -549,6 +550,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::view('data-policy', 'site.help.data-policy')->name('help.data-policy'); Route::view('labs-deprecation', 'site.help.labs-deprecation')->name('help.labs-deprecation'); Route::view('tagging-people', 'site.help.tagging-people')->name('help.tagging-people'); + Route::view('licenses', 'site.help.licenses')->name('help.licenses'); }); Route::get('newsroom/{year}/{month}/{slug}', 'NewsroomController@show'); Route::get('newsroom/archive', 'NewsroomController@archive');