Browse Source

Merge pull request #255 from v2board/dev

1.3
tokumeikoi 4 years ago
parent
commit
95e698dbc8
63 changed files with 2209 additions and 1390 deletions
  1. 18 0
      app/Console/Commands/CheckCommission.php
  2. 42 17
      app/Console/Commands/CheckOrder.php
  3. 41 0
      app/Console/Commands/Test.php
  4. 27 3
      app/Http/Controllers/Admin/ConfigController.php
  5. 50 0
      app/Http/Controllers/Admin/OrderController.php
  6. 22 3
      app/Http/Controllers/Admin/PlanController.php
  7. 18 1
      app/Http/Controllers/Admin/ServerController.php
  8. 10 1
      app/Http/Controllers/Admin/StatController.php
  9. 38 6
      app/Http/Controllers/Admin/TicketController.php
  10. 18 1
      app/Http/Controllers/Admin/TutorialController.php
  11. 2 7
      app/Http/Controllers/Admin/UserController.php
  12. 95 61
      app/Http/Controllers/Client/ClientController.php
  13. 111 0
      app/Http/Controllers/Guest/TelegramController.php
  14. 6 0
      app/Http/Controllers/Passport/AuthController.php
  15. 19 14
      app/Http/Controllers/Server/DeepbworkController.php
  16. 35 13
      app/Http/Controllers/Server/PoseidonController.php
  17. 18 0
      app/Http/Controllers/User/CommController.php
  18. 1 0
      app/Http/Controllers/User/InviteController.php
  19. 30 127
      app/Http/Controllers/User/OrderController.php
  20. 1 0
      app/Http/Controllers/User/PlanController.php
  21. 2 7
      app/Http/Controllers/User/ServerController.php
  22. 20 0
      app/Http/Controllers/User/TelegramController.php
  23. 54 1
      app/Http/Controllers/User/TicketController.php
  24. 5 0
      app/Http/Controllers/User/TutorialController.php
  25. 24 1
      app/Http/Controllers/User/UserController.php
  26. 11 1
      app/Http/Requests/Admin/ConfigSave.php
  27. 34 0
      app/Http/Requests/Admin/OrderAssign.php
  28. 4 2
      app/Http/Requests/Admin/PlanSave.php
  29. 28 0
      app/Http/Requests/Admin/PlanSort.php
  30. 28 0
      app/Http/Requests/Admin/ServerSort.php
  31. 28 0
      app/Http/Requests/Admin/TutorialSort.php
  32. 1 1
      app/Http/Requests/User/OrderSave.php
  33. 30 0
      app/Http/Requests/User/TicketWithdraw.php
  34. 5 0
      app/Http/Routes/AdminRoute.php
  35. 2 0
      app/Http/Routes/GuestRoute.php
  36. 6 0
      app/Http/Routes/UserRoute.php
  37. 43 0
      app/Jobs/SendTelegramJob.php
  38. 1 0
      app/Models/ServerLog.php
  39. 48 0
      app/Services/CouponService.php
  40. 7 0
      app/Services/MailService.php
  41. 107 0
      app/Services/OrderService.php
  42. 34 0
      app/Services/ServerService.php
  43. 46 0
      app/Services/TelegramService.php
  44. 27 0
      app/Services/UserService.php
  45. 18 0
      app/Utils/Helper.php
  46. 1 1
      config/app.php
  47. 31 14
      database/install.sql
  48. 52 0
      database/update.sql
  49. 1 1
      pm2.yaml
  50. 0 0
      public/assets/admin/antd.async.js
  51. 1 1
      public/assets/admin/env.example.js
  52. 0 0
      public/assets/admin/umi.css
  53. 0 0
      public/assets/admin/umi.js
  54. 0 0
      public/assets/user/antd.chunk.css
  55. 1 1
      public/assets/user/env.example.js
  56. 0 0
      public/assets/user/umi.css
  57. 0 0
      public/assets/user/umi.js
  58. 1 0
      resources/rules/.gitignore
  59. 330 300
      resources/rules/default.clash.yaml
  60. 524 0
      resources/rules/default.surfboard.conf
  61. 50 803
      resources/rules/default.surge.conf
  62. 1 1
      resources/views/admin.blade.php
  63. 1 1
      resources/views/app.blade.php

+ 18 - 0
app/Console/Commands/CheckCommission.php

@@ -38,6 +38,24 @@ class CheckCommission extends Command
      * @return mixed
      */
     public function handle()
+    {
+        $this->autoCheck();
+        $this->autoPayCommission();
+    }
+
+    public function autoCheck()
+    {
+        if ((int)config('v2board.commission_auto_check_enable', 1)) {
+            Order::where('commission_status', 0)
+                ->where('status', 3)
+                ->where('updated_at', '<=', strtotime('-3 day', time()))
+                ->update([
+                    'commission_status' => 1
+                ]);
+        }
+    }
+
+    public function autoPayCommission()
     {
         $order = Order::where('commission_status', 1)
             ->where('status', 3)

+ 42 - 17
app/Console/Commands/CheckOrder.php

@@ -9,6 +9,7 @@ use App\Models\User;
 use App\Models\Plan;
 use App\Utils\Helper;
 use App\Models\Coupon;
+use Illuminate\Support\Facades\DB;
 
 class CheckOrder extends Command
 {
@@ -65,10 +66,48 @@ class CheckOrder extends Command
     {
         $user = User::find($order->user_id);
         $plan = Plan::find($order->plan_id);
-        if ((string)$order->cycle === 'onetime_price') {
-            return $this->buyByOneTime($order, $user, $plan);
+
+        if ($order->refund_amount) {
+            $user->balance = $user->balance + $order->refund_amount;
+        }
+        DB::beginTransaction();
+        if ($order->surplus_order_ids) {
+            try {
+                Order::whereIn('id', json_decode($order->surplus_order_ids))->update([
+                    'status' => 4
+                ]);
+            } catch (\Exception $e) {
+                DB::rollback();
+                abort(500, '开通失败');
+            }
+        }
+        switch ((string)$order->cycle) {
+            case 'onetime_price':
+                $this->buyByOneTime($order, $user, $plan);
+                break;
+            case 'reset_price':
+                $this->buyReset($user);
+                break;
+            default:
+                $this->buyByCycle($order, $user, $plan);
         }
-        return $this->buyByCycle($order, $user, $plan);
+        if (!$user->save()) {
+            DB::rollBack();
+            abort(500, '开通失败');
+        }
+        $order->status = 3;
+        if (!$order->save()) {
+            DB::rollBack();
+            abort(500, '开通失败');
+        }
+
+        DB::commit();
+    }
+
+    private function buyReset(User $user)
+    {
+        $user->u = 0;
+        $user->d = 0;
     }
 
     private function buyByCycle(Order $order, User $user, Plan $plan)
@@ -77,9 +116,6 @@ class CheckOrder extends Command
         if ((int)$order->type === 3) {
             $user->expired_at = time();
         }
-        if ($order->refund_amount) {
-            $user->balance = $user->balance + $order->refund_amount;
-        }
         $user->transfer_enable = $plan->transfer_enable * 1073741824;
         if ((int)config('v2board.renew_reset_traffic_enable', 1)) {
             $user->u = 0;
@@ -88,27 +124,16 @@ class CheckOrder extends Command
         $user->plan_id = $plan->id;
         $user->group_id = $plan->group_id;
         $user->expired_at = $this->getTime($order->cycle, $user->expired_at);
-        if ($user->save()) {
-            $order->status = 3;
-            $order->save();
-        }
     }
 
     private function buyByOneTime(Order $order, User $user, Plan $plan)
     {
-        if ($order->refund_amount) {
-            $user->balance = $user->balance + $order->refund_amount;
-        }
         $user->transfer_enable = $plan->transfer_enable * 1073741824;
         $user->u = 0;
         $user->d = 0;
         $user->plan_id = $plan->id;
         $user->group_id = $plan->group_id;
         $user->expired_at = NULL;
-        if ($user->save()) {
-            $order->status = 3;
-            $order->save();
-        }
     }
 
     private function getTime($str, $timestamp)

+ 41 - 0
app/Console/Commands/Test.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+
+class Test extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'test';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+    }
+}

+ 27 - 3
app/Http/Controllers/Admin/ConfigController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Requests\Admin\ConfigSave;
+use App\Services\TelegramService;
 use Illuminate\Http\Request;
 use App\Utils\Dict;
 use App\Http\Controllers\Controller;
@@ -20,6 +21,20 @@ class ConfigController extends Controller
         ]);
     }
 
+    public function setTelegramWebhook(Request $request)
+    {
+        $telegramService = new TelegramService($request->input('telegram_bot_token'));
+        $telegramService->getMe();
+        $telegramService->setWebhook(
+            url(
+                '/api/v1/guest/telegram/webhook?access_token=' . md5(config('v2board.telegram_bot_token', $request->input('telegram_bot_token')))
+            )
+        );
+        return response([
+            'data' => true
+        ]);
+    }
+
     public function fetch()
     {
         // TODO: default should be in Dict
@@ -30,7 +45,8 @@ class ConfigController extends Controller
                     'invite_commission' => config('v2board.invite_commission', 10),
                     'invite_gen_limit' => config('v2board.invite_gen_limit', 5),
                     'invite_never_expire' => config('v2board.invite_never_expire', 0),
-                    'commission_first_time_enable' => config('v2board.commission_first_time_enable', 1)
+                    'commission_first_time_enable' => config('v2board.commission_first_time_enable', 1),
+                    'commission_auto_check_enable' => config('v2board.commission_auto_check_enable', 1)
                 ],
                 'site' => [
                     'safe_mode_enable' => (int)config('v2board.safe_mode_enable', 0),
@@ -43,7 +59,8 @@ class ConfigController extends Controller
                     'try_out_plan_id' => (int)config('v2board.try_out_plan_id', 0),
                     'try_out_hour' => (int)config('v2board.try_out_hour', 1),
                     'email_whitelist_enable' => (int)config('v2board.email_whitelist_enable', 0),
-                    'email_whitelist_suffix' => config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT)
+                    'email_whitelist_suffix' => config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT),
+                    'email_gmail_limit_enable' => config('v2board.email_gmail_limit_enable', 0)
                 ],
                 'subscribe' => [
                     'plan_change_enable' => (int)config('v2board.plan_change_enable', 1),
@@ -64,9 +81,11 @@ class ConfigController extends Controller
                     'stripe_webhook_key' => config('v2board.stripe_webhook_key'),
                     'stripe_currency' => config('v2board.stripe_currency', 'hkd'),
                     // bitpayx
+                    'bitpayx_name' => config('v2board.bitpayx_name', '聚合支付'),
                     'bitpayx_enable' => (int)config('v2board.bitpayx_enable', 0),
                     'bitpayx_appsecret' => config('v2board.bitpayx_appsecret'),
                     // paytaro
+                    'paytaro_name' => config('v2board.paytaro_name', '聚合支付'),
                     'paytaro_enable' => (int)config('v2board.paytaro_enable', 0),
                     'paytaro_app_id' => config('v2board.paytaro_app_id'),
                     'paytaro_app_secret' => config('v2board.paytaro_app_secret')
@@ -79,13 +98,18 @@ class ConfigController extends Controller
                 ],
                 'server' => [
                     'server_token' => config('v2board.server_token'),
-                    'server_license' => config('v2board.server_license')
+                    'server_license' => config('v2board.server_license'),
+                    'server_log_level' => config('v2board.server_log_level', 'none')
                 ],
                 'tutorial' => [
                     'apple_id' => config('v2board.apple_id')
                 ],
                 'email' => [
                     'email_template' => config('v2board.email_template', 'default')
+                ],
+                'telegram' => [
+                    'telegram_bot_enable' => config('v2board.telegram_bot_enable', 0),
+                    'telegram_bot_token' => config('v2board.telegram_bot_token')
                 ]
             ]
         ]);

+ 50 - 0
app/Http/Controllers/Admin/OrderController.php

@@ -2,13 +2,16 @@
 
 namespace App\Http\Controllers\Admin;
 
+use App\Http\Requests\Admin\OrderAssign;
 use App\Http\Requests\Admin\OrderUpdate;
 use App\Services\OrderService;
+use App\Utils\Helper;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Models\Order;
 use App\Models\User;
 use App\Models\Plan;
+use Illuminate\Support\Facades\DB;
 
 class OrderController extends Controller
 {
@@ -23,6 +26,7 @@ class OrderController extends Controller
         if ($request->input('is_commission')) {
             $orderModel->where('invite_user_id', '!=', NULL);
             $orderModel->where('status', 3);
+            $orderModel->where('commission_balance', '>', 0);
         }
         if ($request->input('id')) {
             $orderModel->where('id', $request->input('id'));
@@ -100,4 +104,50 @@ class OrderController extends Controller
             'data' => true
         ]);
     }
+
+    public function assign(OrderAssign $request)
+    {
+        $plan = Plan::find($request->input('plan_id'));
+        $user = User::where('email', $request->input('email'))->first();
+
+        if (!$user) {
+            abort(500, '该用户不存在');
+        }
+
+        if (!$plan) {
+            abort(500, '该订阅不存在');
+        }
+
+        DB::beginTransaction();
+        $order = new Order();
+        $orderService = new OrderService($order);
+        $order->user_id = $user->id;
+        $order->plan_id = $plan->id;
+        $order->cycle = $request->input('cycle');
+        $order->trade_no = Helper::guid();
+        $order->total_amount = $request->input('total_amount');
+
+        if ($order->cycle === 'reset_price') {
+            $order->type = 4;
+        } else if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id) {
+            $order->type = 3;
+        } else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
+            $order->type = 2;
+        } else {
+            $order->type = 1;
+        }
+
+        $orderService->setInvite($user);
+
+        if (!$order->save()) {
+            DB::rollback();
+            abort(500, '订单创建失败');
+        }
+
+        DB::commit();
+
+        return response([
+            'data' => $order->trade_no
+        ]);
+    }
 }

+ 22 - 3
app/Http/Controllers/Admin/PlanController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Requests\Admin\PlanSave;
+use App\Http\Requests\Admin\PlanSort;
 use App\Http\Requests\Admin\PlanUpdate;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
@@ -16,7 +17,7 @@ class PlanController extends Controller
     public function fetch(Request $request)
     {
         return response([
-            'data' => Plan::get()
+            'data' => Plan::orderBy('sort', 'ASC')->get()
         ]);
     }
 
@@ -29,9 +30,12 @@ class PlanController extends Controller
                 abort(500, '该订阅不存在');
             }
             DB::beginTransaction();
-            // update user group id
+            // update user group id and transfer
             try {
-                User::where('plan_id', $plan->id)->update(['group_id' => $plan->group_id]);
+                User::where('plan_id', $plan->id)->update([
+                    'group_id' => $plan->group_id,
+                    'transfer_enable' => $plan->transfer_enable * 1073741824
+                ]);
                 $plan->update($params);
             } catch (\Exception $e) {
                 DB::rollBack();
@@ -91,4 +95,19 @@ class PlanController extends Controller
             'data' => true
         ]);
     }
+
+    public function sort(PlanSort $request)
+    {
+        DB::beginTransaction();
+        foreach ($request->input('plan_ids') as $k => $v) {
+            if (!Plan::find($v)->update(['sort' => $k + 1])) {
+                DB::rollBack();
+                abort(500, '保存失败');
+            }
+        }
+        DB::commit();
+        return response([
+            'data' => true
+        ]);
+    }
 }

+ 18 - 1
app/Http/Controllers/Admin/ServerController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Requests\Admin\ServerSave;
+use App\Http\Requests\Admin\ServerSort;
 use App\Http\Requests\Admin\ServerUpdate;
 use App\Services\ServerService;
 use Illuminate\Http\Request;
@@ -12,12 +13,13 @@ use App\Models\Server;
 use App\Models\Plan;
 use App\Models\User;
 use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
 
 class ServerController extends Controller
 {
     public function fetch(Request $request)
     {
-        $server = Server::get();
+        $server = Server::orderBy('sort', 'ASC')->get();
         for ($i = 0; $i < count($server); $i++) {
             if (!empty($server[$i]['tags'])) {
                 $server[$i]['tags'] = json_decode($server[$i]['tags']);
@@ -206,4 +208,19 @@ class ServerController extends Controller
             'data' => $config
         ]);
     }
+
+    public function sort(ServerSort $request)
+    {
+        DB::beginTransaction();
+        foreach ($request->input('server_ids') as $k => $v) {
+            if (!Server::find($v)->update(['sort' => $k + 1])) {
+                DB::rollBack();
+                abort(500, '保存失败');
+            }
+        }
+        DB::commit();
+        return response([
+            'data' => true
+        ]);
+    }
 }

+ 10 - 1
app/Http/Controllers/Admin/StatController.php

@@ -20,7 +20,7 @@ class StatController extends Controller
             'data' => [
                 'month_income' => Order::where('created_at', '>=', strtotime(date('Y-m-1')))
                     ->where('created_at', '<', time())
-                    ->where('status', '3')
+                    ->whereIn('status', [3, 4])
                     ->sum('total_amount'),
                 'month_register_total' => User::where('created_at', '>=', strtotime(date('Y-m-1')))
                     ->where('created_at', '<', time())
@@ -30,7 +30,16 @@ class StatController extends Controller
                 'commission_pendding_total' => Order::where('commission_status', 0)
                     ->where('invite_user_id', '!=', NULL)
                     ->where('status', 3)
+                    ->where('commission_balance', '>', 0)
                     ->count(),
+                'day_income' => Order::where('created_at', '>=', strtotime(date('Y-m-d')))
+                    ->where('created_at', '<', time())
+                    ->where('status', 3)
+                    ->sum('total_amount'),
+                'last_month_income' => Order::where('created_at', '>=', strtotime('-1 month', strtotime(date('Y-m-1'))))
+                    ->where('created_at', '<', strtotime(date('Y-m-1')))
+                    ->where('status', 3)
+                    ->sum('total_amount')
             ]
         ]);
     }

+ 38 - 6
app/Http/Controllers/Admin/TicketController.php

@@ -2,10 +2,13 @@
 
 namespace App\Http\Controllers\Admin;
 
+use App\Jobs\SendEmailJob;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Models\Ticket;
+use App\Models\User;
 use App\Models\TicketMessage;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
 
 class TicketController extends Controller
@@ -30,17 +33,25 @@ class TicketController extends Controller
                 'data' => $ticket
             ]);
         }
-        $ticket = Ticket::orderBy('created_at', 'DESC')
+        $current = $request->input('current') ? $request->input('current') : 1;
+        $pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
+        $model = Ticket::orderBy('created_at', 'DESC');
+        if ($request->input('status') !== NULL) {
+            $model->where('status', $request->input('status'));
+        }
+        $total = $model->count();
+        $res = $model->forPage($current, $pageSize)
             ->get();
-        for ($i = 0; $i < count($ticket); $i++) {
-            if ($ticket[$i]['last_reply_user_id'] == $request->session()->get('id')) {
-                $ticket[$i]['reply_status'] = 0;
+        for ($i = 0; $i < count($res); $i++) {
+            if ($res[$i]['last_reply_user_id'] == $request->session()->get('id')) {
+                $res[$i]['reply_status'] = 0;
             } else {
-                $ticket[$i]['reply_status'] = 1;
+                $res[$i]['reply_status'] = 1;
             }
         }
         return response([
-            'data' => $ticket
+            'data' => $res,
+            'total' => $total
         ]);
     }
 
@@ -72,6 +83,7 @@ class TicketController extends Controller
             abort(500, '工单回复失败');
         }
         DB::commit();
+        $this->sendEmailNotify($ticket, $ticketMessage);
         return response([
             'data' => true
         ]);
@@ -95,4 +107,24 @@ class TicketController extends Controller
             'data' => true
         ]);
     }
+
+    // 半小时内不再重复通知
+    private function sendEmailNotify(Ticket $ticket, TicketMessage $ticketMessage)
+    {
+        $user = User::find($ticket->user_id);
+        $cacheKey = 'ticket_sendEmailNotify_' . $ticket->user_id;
+        if (!Cache::get($cacheKey)) {
+            Cache::put($cacheKey, 1, 1800);
+            SendEmailJob::dispatch([
+                'email' => $user->email,
+                'subject' => '您在' . config('v2board.app_name', 'V2Board') . '的工单得到了回复',
+                'template_name' => 'notify',
+                'template_value' => [
+                    'name' => config('v2board.app_name', 'V2Board'),
+                    'url' => config('v2board.app_url'),
+                    'content' => "主题:{$ticket->subject}\r\n回复内容:{$ticketMessage->message}"
+                ]
+            ]);
+        }
+    }
 }

+ 18 - 1
app/Http/Controllers/Admin/TutorialController.php

@@ -3,16 +3,18 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Requests\Admin\TutorialSave;
+use App\Http\Requests\Admin\TutorialSort;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Models\Tutorial;
+use Illuminate\Support\Facades\DB;
 
 class TutorialController extends Controller
 {
     public function fetch(Request $request)
     {
         return response([
-            'data' => Tutorial::get()
+            'data' => Tutorial::orderBy('sort', 'ASC')->get()
         ]);
     }
 
@@ -56,6 +58,21 @@ class TutorialController extends Controller
         ]);
     }
 
+    public function sort(TutorialSort $request)
+    {
+        DB::beginTransaction();
+        foreach ($request->input('tutorial_ids') as $k => $v) {
+            if (!Tutorial::find($v)->update(['sort' => $k + 1])) {
+                DB::rollBack();
+                abort(500, '保存失败');
+            }
+        }
+        DB::commit();
+        return response([
+            'data' => true
+        ]);
+    }
+
     public function drop(Request $request)
     {
         if (empty($request->input('id'))) {

+ 2 - 7
app/Http/Controllers/Admin/UserController.php

@@ -47,13 +47,7 @@ class UserController extends Controller
             abort(500, '参数错误');
         }
         return response([
-            'data' => User::select([
-                'email',
-                'u',
-                'd',
-                'transfer_enable',
-                'expired_at'
-            ])->find($request->input('id'))
+            'data' => User::find($request->input('id'))
         ]);
     }
 
@@ -69,6 +63,7 @@ class UserController extends Controller
         }
         if (isset($params['password'])) {
             $params['password'] = password_hash($params['password'], PASSWORD_DEFAULT);
+            $params['password_algo'] = NULL;
         } else {
             unset($params['password']);
         }

+ 95 - 61
app/Http/Controllers/Client/ClientController.php

@@ -19,7 +19,7 @@ class ClientController extends Controller
         $userService = new UserService();
         if ($userService->isAvailable($user)) {
             $servers = Server::where('show', 1)
-                ->orderBy('name')
+                ->orderBy('sort', 'ASC')
                 ->get();
             foreach ($servers as $item) {
                 $groupId = json_decode($item['group_id']);
@@ -39,7 +39,7 @@ class ClientController extends Controller
                 die($this->clash($user, $server));
             }
             if (strpos($_SERVER['HTTP_USER_AGENT'], 'Surfboard') !== false) {
-                die($this->surge($user, $server));
+                die($this->surfboard($user, $server));
             }
             if (strpos($_SERVER['HTTP_USER_AGENT'], 'Surge') !== false) {
                 die($this->surge($user, $server));
@@ -53,7 +53,18 @@ class ClientController extends Controller
         $uri = '';
         foreach ($server as $item) {
             $uri .= "vmess=" . $item->host . ":" . $item->port . ", method=none, password=" . $user->v2ray_uuid . ", fast-open=false, udp-relay=false, tag=" . $item->name;
-            if ($item->network == 'ws') {
+            if ($item->tls) {
+                $tlsSettings = json_decode($item->tlsSettings);
+                if ($item->network === 'tcp') $uri .= ', obfs=over-tls';
+                if (isset($tlsSettings->allowInsecure)) {
+                    // Default: tls-verification=true
+                    $uri .= ', tls-verification=' . ($tlsSettings->allowInsecure ? "false" : "true");
+                }
+                if (isset($tlsSettings->serverName)) {
+                    $uri .= ', obfs-host=' . $tlsSettings->serverName;
+                }
+            }
+            if ($item->network === 'ws') {
                 $uri .= ', obfs=' . ($item->tls ? 'wss' : 'ws');
                 if ($item->networkSettings) {
                     $wsSettings = json_decode($item->networkSettings);
@@ -101,12 +112,12 @@ class ClientController extends Controller
         $proxyGroup = '';
         foreach ($server as $item) {
             // [Proxy]
-            $proxies .= $item->name . ' = vmess, ' . $item->host . ', ' . $item->port . ', username=' . $user->v2ray_uuid;
+            $proxies .= $item->name . ' = vmess, ' . $item->host . ', ' . $item->port . ', username=' . $user->v2ray_uuid . ', tfo=true';
             if ($item->tls) {
                 $tlsSettings = json_decode($item->tlsSettings);
                 $proxies .= ', tls=' . ($item->tls ? "true" : "false");
                 if (isset($tlsSettings->allowInsecure)) {
-                  $proxies .= ', skip-cert-verify=true';
+                  $proxies .= ', skip-cert-verify=' . ($tlsSettings->allowInsecure ? "true" : "false");
                 }
             }
             if ($item->network == 'ws') {
@@ -122,12 +133,66 @@ class ClientController extends Controller
             $proxyGroup .= $item->name . ', ';
         }
 
-        try {
-            $rules = '';
-            foreach (glob(base_path() . '/resources/rules/' . '*.surge.conf') as $file) {
-                $rules = file_get_contents("$file");
+        $defaultConfig = base_path() . '/resources/rules/default.surge.conf';
+        $customConfig = base_path() . '/resources/rules/custom.surge.conf';
+        if (\File::exists($customConfig)) {
+            $config = file_get_contents("$customConfig");
+        } else {
+            $config = file_get_contents("$defaultConfig");
+        }
+
+        // Subscription link
+        $subsURL = 'http';
+        if (isset( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) == 'on') {
+            $subsURL .= 's';
+        }
+        $subsURL .= '://';
+        if ($_SERVER['SERVER_PORT'] != ('80' || '443')) {
+            $subsURL .= $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
+        } else {
+            $subsURL .= $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
+        }
+
+        $config = str_replace('$subs_link',$subsURL,$config);
+        $config = str_replace('$proxies',$proxies,$config);
+        $config = str_replace('$proxy_group',rtrim($proxyGroup, ', '),$config);
+        return $config;
+    }
+
+    private function surfboard($user, $server)
+    {
+        $proxies = '';
+        $proxyGroup = '';
+        foreach ($server as $item) {
+            // [Proxy]
+            $proxies .= $item->name . ' = vmess, ' . $item->host . ', ' . $item->port . ', username=' . $user->v2ray_uuid;
+            if ($item->tls) {
+                $tlsSettings = json_decode($item->tlsSettings);
+                $proxies .= ', tls=' . ($item->tls ? "true" : "false");
+                if (isset($tlsSettings->allowInsecure)) {
+                  $proxies .= ', skip-cert-verify=' . ($tlsSettings->allowInsecure ? "true" : "false");
+                }
             }
-        } catch (\Exception $e) {}
+            if ($item->network == 'ws') {
+                $proxies .= ', ws=true';
+                if ($item->networkSettings) {
+                    $wsSettings = json_decode($item->networkSettings);
+                    if (isset($wsSettings->path)) $proxies .= ', ws-path=' . $wsSettings->path;
+                    if (isset($wsSettings->headers->Host)) $proxies .= ', ws-headers=host:' . $wsSettings->headers->Host;
+                }
+            }
+            $proxies .= "\r\n";
+            // [Proxy Group]
+            $proxyGroup .= $item->name . ', ';
+        }
+
+        $defaultConfig = base_path() . '/resources/rules/default.surfboard.conf';
+        $customConfig = base_path() . '/resources/rules/custom.surfboard.conf';
+        if (\File::exists($customConfig)) {
+            $config = file_get_contents("$customConfig");
+        } else {
+            $config = file_get_contents("$defaultConfig");
+        }
 
         // Subscription link
         $subsURL = 'http';
@@ -141,18 +206,23 @@ class ClientController extends Controller
             $subsURL .= $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
         }
 
-        $rules = str_replace('{subs_link}',$subsURL,$rules);
-        $rules = str_replace('{proxies}',$proxies,$rules);
-        $rules = str_replace('{proxy_group}',rtrim($proxyGroup, ', '),$rules);
-        return $rules;
+        $config = str_replace('$subs_link',$subsURL,$config);
+        $config = str_replace('$proxies',$proxies,$config);
+        $config = str_replace('$proxy_group',rtrim($proxyGroup, ', '),$config);
+        return $config;
     }
 
     private function clash($user, $server)
     {
+        $defaultConfig = base_path() . '/resources/rules/default.clash.yaml';
+        $customConfig = base_path() . '/resources/rules/custom.clash.yaml';
+        if (\File::exists($customConfig)) {
+            $config = Yaml::parseFile($customConfig);
+        } else {
+            $config = Yaml::parseFile($defaultConfig);
+        }
         $proxy = [];
-        $proxyGroup = [];
         $proxies = [];
-        $rules = [];
         foreach ($server as $item) {
             $array = [];
             $array['name'] = $item->name;
@@ -163,8 +233,9 @@ class ClientController extends Controller
             $array['alterId'] = $user->v2ray_alter_id;
             $array['cipher'] = 'auto';
             if ($item->tls) {
+                $tlsSettings = json_decode($item->tlsSettings);
                 $array['tls'] = true;
-                $array['skip-cert-verify'] = true;
+                if (isset($tlsSettings->allowInsecure)) $array['skip-cert-verify'] = ($tlsSettings->allowInsecure ? true : false );
             }
             if ($item->network == 'ws') {
                 $array['network'] = $item->network;
@@ -180,49 +251,12 @@ class ClientController extends Controller
             array_push($proxies, $item->name);
         }
 
-        array_push($proxyGroup, [
-            'name' => 'auto',
-            'type' => 'url-test',
-            'proxies' => $proxies,
-            'url' => 'https://www.bing.com',
-            'interval' => 300
-        ]);
-        array_push($proxyGroup, [
-            'name' => 'fallback-auto',
-            'type' => 'fallback',
-            'proxies' => $proxies,
-            'url' => 'https://www.bing.com',
-            'interval' => 300
-        ]);
-        array_push($proxyGroup, [
-            'name' => 'select',
-            'type' => 'select',
-            'proxies' => array_merge($proxies, [
-                'auto',
-                'fallback-auto'
-            ])
-        ]);
-
-        try {
-            $rules = [];
-            foreach (glob(base_path() . '/resources/rules/' . '*.clash.yaml') as $file) {
-                $rules = array_merge($rules, Yaml::parseFile($file)['Rule']);
-            }
-        } catch (\Exception $e) {}
-
-        $config = [
-            'port' => 7890,
-            'socks-port' => 7891,
-            'allow-lan' => false,
-            'mode' => 'Rule',
-            'log-level' => 'info',
-            'external-controller' => '0.0.0.0:9090',
-            'secret' => '',
-            'Proxy' => $proxy,
-            'Proxy Group' => $proxyGroup,
-            'Rule' => $rules
-        ];
-
-        return Yaml::dump($config);
+        $config['Proxy'] = array_merge($config['Proxy'] ? $config['Proxy'] : [], $proxy);
+        foreach ($config['Proxy Group'] as $k => $v) {
+            $config['Proxy Group'][$k]['proxies'] = array_merge($config['Proxy Group'][$k]['proxies'], $proxies);
+        }
+        $yaml = Yaml::dump($config);
+        $yaml = str_replace('$app_name', config('v2board.app_name', 'V2Board'), $yaml);
+        return $yaml;
     }
 }

+ 111 - 0
app/Http/Controllers/Guest/TelegramController.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App\Http\Controllers\Guest;
+
+use App\Services\TelegramService;
+use Illuminate\Http\Request;
+use App\Http\Controllers\Controller;
+use App\Models\User;
+use App\Utils\Helper;
+
+class TelegramController extends Controller
+{
+    protected $msg;
+
+    public function __construct(Request $request)
+    {
+        if ($request->input('access_token') !== md5(config('v2board.telegram_bot_token'))) {
+            abort(500, 'authentication failed');
+        }
+    }
+
+    public function webhook(Request $request)
+    {
+        $this->msg = $this->getMessage($request->input());
+        if (!$this->msg) return;
+        try {
+            switch($this->msg->command) {
+                case '/bind': $this->bind();
+                    break;
+                case '/traffic': $this->traffic();
+                    break;
+                default: $this->help();
+            }
+        } catch (\Exception $e) {
+            $telegramService = new TelegramService();
+            $telegramService->sendMessage($this->msg->chat_id, $e->getMessage());
+        }
+    }
+
+    private function getMessage(array $data)
+    {
+        if (!isset($data['message'])) return false;
+        $obj = new \StdClass();
+        $obj->is_private = $data['message']['chat']['type'] === 'private' ? true : false;
+        if (!isset($data['message']['text'])) return false;
+        $text = explode(' ', $data['message']['text']);
+        $obj->command = $text[0];
+        $obj->args = array_slice($text, 1);
+        $obj->chat_id = $data['message']['chat']['id'];
+        $obj->message_id = $data['message']['message_id'];
+        return $obj;
+    }
+
+    private function bind()
+    {
+        $msg = $this->msg;
+        if (!$msg->is_private) return;
+        if (!isset($msg->args[0])) {
+            abort(500, '参数有误,请携带订阅地址发送');
+        }
+        $subscribeUrl = $msg->args[0];
+        $subscribeUrl = parse_url($subscribeUrl);
+        parse_str($subscribeUrl['query'], $query);
+        $token = $query['token'];
+        if (!$token) {
+            abort(500, '订阅地址无效');
+        }
+        $user = User::where('token', $token)->first();
+        if (!$user) {
+            abort(500, '用户不存在');
+        }
+        $user->telegram_id = $msg->chat_id;
+        if (!$user->save()) {
+            abort(500, '设置失败');
+        }
+        $telegramService = new TelegramService();
+        $telegramService->sendMessage($msg->chat_id, '绑定成功');
+    }
+
+    private function help()
+    {
+        $msg = $this->msg;
+        if (!$msg->is_private) return;
+        $telegramService = new TelegramService();
+        $commands = [
+            '/bind 订阅地址 - 绑定你的' . config('v2board.app_name', 'V2Board') . '账号',
+            '/traffic - 查询流量信息'
+        ];
+        $text = implode(PHP_EOL, $commands);
+        $telegramService->sendMessage($msg->chat_id, "你可以使用以下命令进行操作:\n\n$text", 'markdown');
+    }
+
+    private function traffic()
+    {
+        $msg = $this->msg;
+        if (!$msg->is_private) return;
+        $user = User::where('telegram_id', $msg->chat_id)->first();
+        $telegramService = new TelegramService();
+        if (!$user) {
+            $this->help();
+            $telegramService->sendMessage($msg->chat_id, '没有查询到您的用户信息,请先绑定账号', 'markdown');
+            return;
+        }
+        $transferEnable = Helper::trafficConvert($user->transfer_enable);
+        $up = Helper::trafficConvert($user->u);
+        $down = Helper::trafficConvert($user->d);
+        $remaining = Helper::trafficConvert($user->transfer_enable - ($user->u + $user->d));
+        $text = "🚥流量查询\n———————————————\n计划流量:`{$transferEnable}`\n已用上行:`{$up}`\n已用下行:`{$down}`\n剩余流量:`{$remaining}`";
+        $telegramService->sendMessage($msg->chat_id, $text, 'markdown');
+    }
+}

+ 6 - 0
app/Http/Controllers/Passport/AuthController.php

@@ -27,6 +27,12 @@ class AuthController extends Controller
                 abort(500, '邮箱后缀不处于白名单中');
             }
         }
+        if ((int)config('v2board.email_gmail_limit_enable', 0)) {
+            $prefix = explode('@', $request->input('email'))[0];
+            if (strpos($prefix, '.') !== false || strpos($prefix, '+') !== false) {
+                abort(500, '不支持Gmail别名邮箱');
+            }
+        }
         if ((int)config('v2board.stop_register', 0)) {
             abort(500, '本站已关闭注册');
         }

+ 19 - 14
app/Http/Controllers/Server/DeepbworkController.php

@@ -3,11 +3,13 @@
 namespace App\Http\Controllers\Server;
 
 use App\Services\ServerService;
+use App\Services\UserService;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Models\User;
 use App\Models\Server;
 use App\Models\ServerLog;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Cache;
 
@@ -63,28 +65,31 @@ class DeepbworkController extends Controller
         $server = Server::find($request->input('node_id'));
         if (!$server) {
             return response([
-                'ret' => 1,
-                'msg' => 'ok'
+                'ret' => 0,
+                'msg' => 'server is not found'
             ]);
         }
         $data = file_get_contents('php://input');
         $data = json_decode($data, true);
+        $serverService = new ServerService();
+        $userService = new UserService();
         foreach ($data as $item) {
             $u = $item['u'] * $server->rate;
             $d = $item['d'] * $server->rate;
-            $user = User::find($item['user_id']);
-            $user->t = time();
-            $user->u = $user->u + $u;
-            $user->d = $user->d + $d;
-            $user->save();
+            if (!$userService->trafficFetch($u, $d, $item['user_id'])) {
+                return response([
+                    'ret' => 0,
+                    'msg' => 'user fetch fail'
+                ]);
+            }
 
-            $serverLog = new ServerLog();
-            $serverLog->user_id = $item['user_id'];
-            $serverLog->server_id = $request->input('node_id');
-            $serverLog->u = $item['u'];
-            $serverLog->d = $item['d'];
-            $serverLog->rate = $server->rate;
-            $serverLog->save();
+            $serverService->log(
+                $item['user_id'],
+                $request->input('node_id'),
+                $item['u'],
+                $item['d'],
+                $server->rate
+            );
         }
 
         return response([

+ 35 - 13
app/Http/Controllers/Server/PoseidonController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Server;
 
 use App\Services\ServerService;
+use App\Services\UserService;
 use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Models\User;
@@ -16,6 +17,13 @@ class PoseidonController extends Controller
 {
     CONST SERVER_CONFIG = '{"api":{"services":["HandlerService","StatsService"],"tag":"api"},"stats":{},"inbound":{"port":443,"protocol":"vmess","settings":{"clients":[]},"sniffing":{"enabled": true,"destOverride": ["http","tls"]},"streamSettings":{"network":"tcp"},"tag":"proxy"},"inboundDetour":[{"listen":"0.0.0.0","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"outbound":{"protocol":"freedom","settings":{}},"outboundDetour":[{"protocol":"blackhole","settings":{},"tag":"block"}],"routing":{"rules":[{"inboundTag":"api","outboundTag":"api","type":"field"}]},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}';
 
+    public $poseidonVersion;
+
+    public function __construct(Request $request)
+    {
+        $this->poseidonVersion = $request->input('poseidon_version');
+    }
+
     // 后端获取用户
     public function user(Request $request)
     {
@@ -58,22 +66,22 @@ class PoseidonController extends Controller
         }
         $data = file_get_contents('php://input');
         $data = json_decode($data, true);
+        $serverService = new ServerService();
+        $userService = new UserService();
         foreach ($data as $item) {
             $u = $item['u'] * $server->rate;
             $d = $item['d'] * $server->rate;
-            $user = User::find($item['user_id']);
-            $user->t = time();
-            $user->u = $user->u + $u;
-            $user->d = $user->d + $d;
-            $user->save();
-
-            $serverLog = new ServerLog();
-            $serverLog->user_id = $item['user_id'];
-            $serverLog->server_id = $request->input('node_id');
-            $serverLog->u = $item['u'];
-            $serverLog->d = $item['d'];
-            $serverLog->rate = $server->rate;
-            $serverLog->save();
+            if (!$userService->trafficFetch($u, $d, $item['user_id'])) {
+                return $this->error("user fetch fail", 500);
+            }
+
+            $serverService->log(
+                $item['user_id'],
+                $request->input('node_id'),
+                $item['u'],
+                $item['d'],
+                $server->rate
+            );
         }
 
         return $this->success('');
@@ -96,6 +104,20 @@ class PoseidonController extends Controller
             $json->poseidon = [
               'license_key' => (string)config('v2board.server_license'),
             ];
+            if ($this->poseidonVersion >= 'v1.5.0') {
+                // don't need it after v1.5.0
+                unset($json->inboundDetour);
+                unset($json->stats);
+                unset($json->api);
+                array_shift($json->routing->rules);
+            }
+
+            foreach($json->policy->levels as &$level) {
+                $level->handshake = 2;
+                $level->uplinkOnly = 2;
+                $level->downlinkOnly = 2;
+                $level->connIdle = 60;
+            }
 
             return $this->success($json);
         } catch (\Exception $e) {

+ 18 - 0
app/Http/Controllers/User/CommController.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Http\Controllers\User;
+
+use Illuminate\Http\Request;
+use App\Http\Controllers\Controller;
+
+class CommController extends Controller
+{
+    public function config()
+    {
+        return response([
+            'data' => [
+                'isTelegram' => (int)config('v2board.telegram_bot_enable', 0)
+            ]
+        ]);
+    }
+}

+ 1 - 0
app/Http/Controllers/User/InviteController.php

@@ -28,6 +28,7 @@ class InviteController extends Controller
     {
         return response([
             'data' => Order::where('invite_user_id', $request->session()->get('id'))
+                ->where('commission_balance', '>', 0)
                 ->where('status', 3)
                 ->select([
                     'id',

+ 30 - 127
app/Http/Controllers/User/OrderController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\User;
 
 use App\Http\Controllers\Controller;
 use App\Http\Requests\User\OrderSave;
+use App\Services\CouponService;
 use App\Services\OrderService;
 use App\Services\UserService;
 use Illuminate\Http\Request;
@@ -62,64 +63,11 @@ class OrderController extends Controller
         ]);
     }
 
-    private function isNotCompleteOrderByUserId($userId)
-    {
-        $order = Order::whereIn('status', [0, 1])
-            ->where('user_id', $userId)
-            ->first();
-        if (!$order) {
-            return false;
-        }
-        return true;
-    }
-
-    // surplus value
-    private function getSurplusValue(User $user)
-    {
-        $plan = Plan::find($user->plan_id);
-        if ($user->expired_at === NULL) {
-            return $this->getSurplusValueByOneTime($user, $plan);
-        } else {
-            return $this->getSurplusValueByCycle($user, $plan);
-        }
-    }
-
-    private function getSurplusValueByOneTime(User $user, Plan $plan)
-    {
-        $trafficUnitPrice = $plan->onetime_price / $plan->transfer_enable;
-        if ($user->discount && $trafficUnitPrice) {
-            $trafficUnitPrice = $trafficUnitPrice - ($trafficUnitPrice * $user->discount / 100);
-        }
-        $notUsedTrafficPrice = $plan->transfer_enable - (($user->u + $user->d) / 1073741824);
-        $result = $trafficUnitPrice * $notUsedTrafficPrice;
-        return $result > 0 ? $result : 0;
-    }
-
-    private function getSurplusValueByCycle(User $user, Plan $plan)
-    {
-        $price = 0;
-        if ($plan->month_price) {
-            $price = $plan->month_price / (31536000 / 12);
-        } else if ($plan->quarter_price) {
-            $price = $plan->quarter_price / (31536000 / 4);
-        } else if ($plan->half_year_price) {
-            $price = $plan->half_year_price / (31536000 / 2);
-        } else if ($plan->year_price) {
-            $price = $plan->year_price / 31536000;
-        }
-        // exclude discount
-        if ($user->discount && $price) {
-            $price = $price - ($price * $user->discount / 100);
-        }
-        $remainingDay = $user->expired_at - time();
-        $result = $remainingDay * $price;
-        return $result > 0 ? $result : 0;
-    }
-
     public function save(OrderSave $request)
     {
-        if ($this->isNotCompleteOrderByUserId($request->session()->get('id'))) {
-            abort(500, '存在未付款订单,请取消后再试');
+        $userService = new UserService();
+        if ($userService->isNotCompleteOrderByUserId($request->session()->get('id'))) {
+            abort(500, '您有未付款或开通中的订单,请稍后或取消再试');
         }
 
         $plan = Plan::find($request->input('plan_id'));
@@ -130,7 +78,9 @@ class OrderController extends Controller
         }
 
         if ((!$plan->show && !$plan->renew) || (!$plan->show && $user->plan_id !== $plan->id)) {
-            abort(500, '该订阅已售罄');
+            if ($request->input('cycle') !== 'reset_price') {
+                abort(500, '该订阅已售罄');
+            }
         }
 
         if (!$plan->renew && $user->plan_id == $plan->id) {
@@ -138,87 +88,37 @@ class OrderController extends Controller
         }
 
         if ($plan[$request->input('cycle')] === NULL) {
+            if ($request->input('cycle') === 'reset_price') {
+                abort(500, '该订阅当前不支持重置流量');
+            }
             abort(500, '该订阅周期无法进行购买,请选择其他周期');
         }
 
-        if ($request->input('coupon_code')) {
-            $coupon = Coupon::where('code', $request->input('coupon_code'))->first();
-            if (!$coupon) {
-                abort(500, '优惠券无效');
-            }
-            if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
-                abort(500, '优惠券已无可用次数');
-            }
-            if (time() < $coupon->started_at) {
-                abort(500, '优惠券还未到可用时间');
-            }
-            if (time() > $coupon->ended_at) {
-                abort(500, '优惠券已过期');
-            }
+        if ($request->input('cycle') === 'reset_price' && !$user->plan_id) {
+            abort(500, '必须存在订阅才可以购买流量重置包');
         }
 
         DB::beginTransaction();
         $order = new Order();
+        $orderService = new OrderService($order);
         $order->user_id = $request->session()->get('id');
         $order->plan_id = $plan->id;
         $order->cycle = $request->input('cycle');
         $order->trade_no = Helper::guid();
         $order->total_amount = $plan[$request->input('cycle')];
-        // coupon start
-        if (isset($coupon)) {
-            switch ($coupon->type) {
-                case 1:
-                    $order->discount_amount = $coupon->value;
-                    break;
-                case 2:
-                    $order->discount_amount = $order->total_amount * ($coupon->value / 100);
-                    break;
-            }
-            if ($coupon->limit_use !== NULL) {
-                $coupon->limit_use = $coupon->limit_use - 1;
-                if (!$coupon->save()) {
-                    DB::rollback();
-                    abort(500, '优惠券使用失败');
-                }
-            }
-        }
-        // coupon complete
-        // discount start
-        if ($user->discount) {
-            $order->discount_amount = $order->discount_amount + ($order->total_amount * ($user->discount / 100));
-        }
-        // discount end
-        $order->total_amount = $order->total_amount - $order->discount_amount;
-        // renew and change subscribe process
-        if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id) {
-            if (!(int)config('v2board.plan_change_enable', 1)) abort(500, '目前不允许更改订阅,请联系客服或提交工单');
-            $order->type = 3;
-            $order->surplus_amount = $this->getSurplusValue($user);
-            if ($order->surplus_amount >= $order->total_amount) {
-                $order->refund_amount = $order->surplus_amount - $order->total_amount;
-                $order->total_amount = 0;
-            } else {
-                $order->total_amount = $order->total_amount - $order->surplus_amount;
-            }
-        } else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
-            $order->type = 2;
-        } else {
-            $order->type = 1;
-        }
-        // invite process
-        if ($user->invite_user_id && $order->total_amount > 0) {
-            $order->invite_user_id = $user->invite_user_id;
-            $commissionFirstTime = (int)config('v2board.commission_first_time_enable', 1);
-            if (!$commissionFirstTime || ($commissionFirstTime && !Order::where('user_id', $user->id)->where('status', 3)->first())) {
-                $inviter = User::find($user->invite_user_id);
-                if ($inviter && $inviter->commission_rate) {
-                    $order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
-                } else {
-                    $order->commission_balance = $order->total_amount * (config('v2board.invite_commission', 10) / 100);
-                }
+
+        if ($request->input('coupon_code')) {
+            $couponService = new CouponService($request->input('coupon_code'));
+            if (!$couponService->use($order)) {
+                DB::rollBack();
+                abort(500, '优惠券使用失败');
             }
         }
-        // use balance
+
+        $orderService->setVipDiscount($user);
+        $orderService->setOrderType($user);
+        $orderService->setInvite($user);
+
         if ($user->balance && $order->total_amount > 0) {
             $remainingBalance = $user->balance - $order->total_amount;
             $userService = new UserService();
@@ -267,7 +167,10 @@ class OrderController extends Controller
             $order->total_amount = 0;
             $order->status = 1;
             $order->save();
-            exit();
+            return response([
+                'type' => -1,
+                'data' => true
+            ]);
         }
         switch ($method) {
             // return type => 0: QRCode / 1: URL
@@ -363,7 +266,7 @@ class OrderController extends Controller
 
         if ((int)config('v2board.bitpayx_enable')) {
             $bitpayX = new \StdClass();
-            $bitpayX->name = '聚合支付';
+            $bitpayX->name = config('v2board.bitpayx_name', '聚合支付');
             $bitpayX->method = 4;
             $bitpayX->icon = 'wallet';
             array_push($data, $bitpayX);
@@ -371,7 +274,7 @@ class OrderController extends Controller
 
         if ((int)config('v2board.paytaro_enable')) {
             $obj = new \StdClass();
-            $obj->name = '聚合支付';
+            $obj->name = config('v2board.paytaro_name', '聚合支付');
             $obj->method = 5;
             $obj->icon = 'wallet';
             array_push($data, $obj);

+ 1 - 0
app/Http/Controllers/User/PlanController.php

@@ -21,6 +21,7 @@ class PlanController extends Controller
             ]);
         }
         $plan = Plan::where('show', 1)
+            ->orderBy('sort', 'ASC')
             ->get();
         return response([
             'data' => $plan

+ 2 - 7
app/Http/Controllers/User/ServerController.php

@@ -21,7 +21,7 @@ class ServerController extends Controller
         $userService = new UserService();
         if ($userService->isAvailable($user)) {
             $servers = Server::where('show', 1)
-                ->orderBy('name')
+                ->orderBy('sort', 'ASC')
                 ->get();
             foreach ($servers as $item) {
                 $groupId = json_decode($item['group_id']);
@@ -60,17 +60,12 @@ class ServerController extends Controller
             case 2:
                 $serverLogModel->where('created_at', '>=', strtotime(date('Y-m-1')));
         }
-        $sum = [
-            'u' => $serverLogModel->sum('u'),
-            'd' => $serverLogModel->sum('d')
-        ];
         $total = $serverLogModel->count();
         $res = $serverLogModel->forPage($current, $pageSize)
             ->get();
         return response([
             'data' => $res,
-            'total' => $total,
-            'sum' => $sum
+            'total' => $total
         ]);
     }
 }

+ 20 - 0
app/Http/Controllers/User/TelegramController.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Controllers\User;
+
+use App\Http\Controllers\Controller;
+use App\Services\TelegramService;
+
+class TelegramController extends Controller
+{
+    public function getBotInfo()
+    {
+        $telegramService = new TelegramService();
+        $response = $telegramService->getMe();
+        return response([
+            'data' => [
+                'username' => $response->result->username
+            ]
+        ]);
+    }
+}

+ 54 - 1
app/Http/Controllers/User/TicketController.php

@@ -4,10 +4,12 @@ namespace App\Http\Controllers\User;
 
 use App\Http\Controllers\Controller;
 use App\Http\Requests\User\TicketSave;
+use App\Http\Requests\User\TicketWithdraw;
+use App\Jobs\SendTelegramJob;
+use App\Models\User;
 use Illuminate\Http\Request;
 use App\Models\Ticket;
 use App\Models\TicketMessage;
-use App\Utils\Helper;
 use Illuminate\Support\Facades\DB;
 
 class TicketController extends Controller
@@ -75,6 +77,7 @@ class TicketController extends Controller
             abort(500, '工单创建失败');
         }
         DB::commit();
+        $this->sendNotify($ticket, $ticketMessage);
         return response([
             'data' => true
         ]);
@@ -112,6 +115,7 @@ class TicketController extends Controller
             abort(500, '工单回复失败');
         }
         DB::commit();
+        $this->sendNotify($ticket, $ticketMessage);
         return response([
             'data' => true
         ]);
@@ -144,4 +148,53 @@ class TicketController extends Controller
             ->orderBy('id', 'DESC')
             ->first();
     }
+
+    public function withdraw(TicketWithdraw $request)
+    {
+        DB::beginTransaction();
+        $subject = '[提现申请]本工单由系统发出';
+        $ticket = Ticket::create([
+            'subject' => $subject,
+            'level' => 2,
+            'user_id' => $request->session()->get('id'),
+            'last_reply_user_id' => $request->session()->get('id')
+        ]);
+        if (!$ticket) {
+            DB::rollback();
+            abort(500, '工单创建失败');
+        }
+        $methodText = [
+            'alipay' => '支付宝',
+            'paypal' => '贝宝(Paypal)',
+            'usdt' => 'USDT',
+            'btc' => '比特币'
+        ];
+        $message = "提现方式:{$methodText[$request->input('withdraw_method')]}\r\n提现账号:{$request->input('withdraw_account')}\r\n";
+        $ticketMessage = TicketMessage::create([
+            'user_id' => $request->session()->get('id'),
+            'ticket_id' => $ticket->id,
+            'message' => $message
+        ]);
+        if (!$ticketMessage) {
+            DB::rollback();
+            abort(500, '工单创建失败');
+        }
+        DB::commit();
+        $this->sendNotify($ticket, $ticketMessage);
+        return response([
+            'data' => true
+        ]);
+    }
+
+    private function sendNotify(Ticket $ticket, TicketMessage $ticketMessage)
+    {
+        if (!config('v2board.telegram_bot_enable', 0)) return;
+        $users = User::where('is_admin', 1)
+            ->where('telegram_id', '!=', NULL)
+            ->get();
+        foreach ($users as $user) {
+            $text = "📮工单提醒 #{$ticket->id}\n———————————————\n主题:\n`{$ticket->subject}`\n内容:\n`{$ticketMessage->message}`";
+            SendTelegramJob::dispatch($user->telegram_id, $text);
+        }
+    }
 }

+ 5 - 0
app/Http/Controllers/User/TutorialController.php

@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
 use Illuminate\Http\Request;
 use App\Models\User;
 use App\Models\Tutorial;
+use Illuminate\Support\Facades\DB;
 
 class TutorialController extends Controller
 {
@@ -51,6 +52,7 @@ class TutorialController extends Controller
         }
         $tutorial = Tutorial::select(['id', 'category_id', 'title'])
             ->where('show', 1)
+            ->orderBy('sort', 'ASC')
             ->get()
             ->groupBy('category_id');
         $user = User::find($request->session()->get('id'));
@@ -72,6 +74,9 @@ class TutorialController extends Controller
             base64_encode($response['data']['safe_area_var']['subscribe_url'])
         );
         // end
+        // fuck support surge urlencode subscribe
+        $response['data']['safe_area_var']['ue_subscribe_url'] = urlencode($response['data']['safe_area_var']['subscribe_url']);
+        // end
         return response($response);
     }
 }

+ 24 - 1
app/Http/Controllers/User/UserController.php

@@ -62,7 +62,8 @@ class UserController extends Controller
                 'commission_balance',
                 'plan_id',
                 'discount',
-                'commission_rate'
+                'commission_rate',
+                'telegram_id'
             ])
             ->first();
         $user['avatar_url'] = 'https://cdn.v2ex.com/gravatar/' . md5($user->email) . '?s=64&d=identicon';
@@ -137,4 +138,26 @@ class UserController extends Controller
             'data' => true
         ]);
     }
+
+    public function transfer(Request $request)
+    {
+        $user = User::find($request->session()->get('id'));
+        if (!$user) {
+            abort(500, '该用户不存在');
+        }
+        if ($request->input('transfer_amount') <= 0) {
+            abort(500, '参数错误');
+        }
+        if ($request->input('transfer_amount') > $user->commission_balance) {
+            abort(500, '推广佣金余额不足');
+        }
+        $user->commission_balance = $user->commission_balance - $request->input('transfer_amount');
+        $user->balance = $user->balance + $request->input('transfer_amount');
+        if (!$user->save()) {
+            abort(500, '划转失败');
+        }
+        return response([
+            'data' => true
+        ]);
+    }
 }

+ 11 - 1
app/Http/Requests/Admin/ConfigSave.php

@@ -14,6 +14,7 @@ class ConfigSave extends FormRequest
         'invite_gen_limit' => 'integer',
         'invite_never_expire' => 'in:0,1',
         'commission_first_time_enable' => 'in:0,1',
+        'commission_auto_check_enable' => 'in:0,1',
         // site
         'stop_register' => 'in:0,1',
         'email_verify' => 'in:0,1',
@@ -26,6 +27,7 @@ class ConfigSave extends FormRequest
         'try_out_hour' => 'numeric',
         'email_whitelist_enable' => 'in:0,1',
         'email_whitelist_suffix' => '',
+        'email_gmail_limit_enable' => 'in:0,1',
         // subscribe
         'plan_change_enable' => 'in:0,1',
         'reset_traffic_method' => 'in:0,1',
@@ -33,6 +35,7 @@ class ConfigSave extends FormRequest
         // server
         'server_token' => 'nullable|min:16',
         'server_license' => 'nullable',
+        'server_log_level' => 'nullable|in:debug,info,warning,error,none',
         // alipay
         'alipay_enable' => 'in:0,1',
         'alipay_appid' => 'nullable|integer|min:16',
@@ -46,9 +49,11 @@ class ConfigSave extends FormRequest
         'stripe_webhook_key' => '',
         'stripe_currency' => 'in:hkd,usd,sgd,eur,gbp',
         // bitpayx
+        'bitpayx_name' => '',
         'bitpayx_enable' => 'in:0,1',
         'bitpayx_appsecret' => '',
         // paytaro
+        'paytaro_name' => '',
         'paytaro_enable' => 'in:0,1',
         'paytaro_app_id' => '',
         'paytaro_app_secret' => '',
@@ -61,7 +66,12 @@ class ConfigSave extends FormRequest
         'apple_id' => 'email',
         'apple_id_password' => '',
         // email
-        'email_template' => ''
+        'email_template' => '',
+        // telegram
+        'telegram_bot_enable' => 'in:0,1',
+        'telegram_bot_token' => '',
+        'telegram_discuss_id' => '',
+        'telegram_channel_id' => ''
     ];
 
     /**

+ 34 - 0
app/Http/Requests/Admin/OrderAssign.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class OrderAssign extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'plan_id' => 'required',
+            'email' => 'required',
+            'total_amount' => 'required',
+            'cycle' => 'required|in:month_price,quarter_price,half_year_price,year_price,onetime_price,reset_price'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'plan_id.required' => '订阅不能为空',
+            'email.required' => '邮箱不能为空',
+            'total_amount.required' => '支付金额不能为空',
+            'cycle.required' => '订阅周期不能为空',
+            'cycle.in' => '订阅周期格式有误'
+        ];
+    }
+}

+ 4 - 2
app/Http/Requests/Admin/PlanSave.php

@@ -15,7 +15,8 @@ class PlanSave extends FormRequest
         'quarter_price' => 'nullable|integer',
         'half_year_price' => 'nullable|integer',
         'year_price' => 'nullable|integer',
-        'onetime_price' => 'nullable|integer'
+        'onetime_price' => 'nullable|integer',
+        'reset_price' => 'nullable|integer'
     ];
     /**
      * Get the validation rules that apply to the request.
@@ -39,7 +40,8 @@ class PlanSave extends FormRequest
             'quarter_price.integer' => '季付金额格式有误',
             'half_year_price.integer' => '半年付金额格式有误',
             'year_price.integer' => '年付金额格式有误',
-            'onetime_price.integer' => '一次性金额有误'
+            'onetime_price.integer' => '一次性金额有误',
+            'reset_price.integer' => '流量重置包金额有误'
         ];
     }
 }

+ 28 - 0
app/Http/Requests/Admin/PlanSort.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class PlanSort extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'plan_ids' => 'required|array'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'plan_ids.required' => '订阅计划ID不能为空',
+            'plan_ids.array' => '订阅计划ID格式有误'
+        ];
+    }
+}

+ 28 - 0
app/Http/Requests/Admin/ServerSort.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ServerSort extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'server_ids' => 'required|array'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'server_ids.required' => '服务器ID不能为空',
+            'server_ids.array' => '服务器ID格式有误'
+        ];
+    }
+}

+ 28 - 0
app/Http/Requests/Admin/TutorialSort.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class TutorialSort extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'tutorial_ids' => 'required|array'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'tutorial_ids.required' => '教程ID不能为空',
+            'tutorial_ids.array' => '教程ID格式有误'
+        ];
+    }
+}

+ 1 - 1
app/Http/Requests/User/OrderSave.php

@@ -15,7 +15,7 @@ class OrderSave extends FormRequest
     {
         return [
             'plan_id' => 'required',
-            'cycle' => 'required|in:month_price,quarter_price,half_year_price,year_price,onetime_price'
+            'cycle' => 'required|in:month_price,quarter_price,half_year_price,year_price,onetime_price,reset_price'
         ];
     }
 

+ 30 - 0
app/Http/Requests/User/TicketWithdraw.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests\User;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class TicketWithdraw  extends FormRequest
+{
+    /**
+     * Get the validation rules that apply to the request.
+     *
+     * @return array
+     */
+    public function rules()
+    {
+        return [
+            'withdraw_method' => 'required|in:alipay,paypal,usdt,btc',
+            'withdraw_account' => 'required'
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'withdraw_method.required' => '提现方式不能为空',
+            'withdraw_method.in' => '提现方式不支持',
+            'withdraw_account.required' => '提现账号不能为空'
+        ];
+    }
+}

+ 5 - 0
app/Http/Routes/AdminRoute.php

@@ -15,11 +15,13 @@ class AdminRoute
             $router->get ('/config/fetch', 'Admin\\ConfigController@fetch');
             $router->post('/config/save', 'Admin\\ConfigController@save');
             $router->get ('/config/getEmailTemplate', 'Admin\\ConfigController@getEmailTemplate');
+            $router->post('/config/setTelegramWebhook', 'Admin\\ConfigController@setTelegramWebhook');
             // Plan
             $router->get ('/plan/fetch', 'Admin\\PlanController@fetch');
             $router->post('/plan/save', 'Admin\\PlanController@save');
             $router->post('/plan/drop', 'Admin\\PlanController@drop');
             $router->post('/plan/update', 'Admin\\PlanController@update');
+            $router->post('/plan/sort', 'Admin\\PlanController@sort');
             // Server
             $router->get ('/server/fetch', 'Admin\\ServerController@fetch');
             $router->post('/server/save', 'Admin\\ServerController@save');
@@ -30,10 +32,12 @@ class AdminRoute
             $router->post('/server/update', 'Admin\\ServerController@update');
             $router->post('/server/copy', 'Admin\\ServerController@copy');
             $router->post('/server/viewConfig', 'Admin\\ServerController@viewConfig');
+            $router->post('/server/sort', 'Admin\\ServerController@sort');
             // Order
             $router->get ('/order/fetch', 'Admin\\OrderController@fetch');
             $router->post('/order/repair', 'Admin\\OrderController@repair');
             $router->post('/order/update', 'Admin\\OrderController@update');
+            $router->post('/order/assign', 'Admin\\OrderController@assign');
             // User
             $router->get ('/user/fetch', 'Admin\\UserController@fetch');
             $router->post('/user/update', 'Admin\\UserController@update');
@@ -60,6 +64,7 @@ class AdminRoute
             $router->post('/tutorial/save', 'Admin\\TutorialController@save');
             $router->post('/tutorial/show', 'Admin\\TutorialController@show');
             $router->post('/tutorial/drop', 'Admin\\TutorialController@drop');
+            $router->post('/tutorial/sort', 'Admin\\TutorialController@sort');
         });
     }
 }

+ 2 - 0
app/Http/Routes/GuestRoute.php

@@ -17,6 +17,8 @@ class GuestRoute
             $router->post('/order/stripeNotify', 'Guest\\OrderController@stripeNotify');
             $router->post('/order/bitpayXNotify', 'Guest\\OrderController@bitpayXNotify');
             $router->post('/order/payTaroNotify', 'Guest\\OrderController@payTaroNotify');
+            // Telegram
+            $router->post('/telegram/webhook', 'Guest\\TelegramController@webhook');
         });
     }
 }

+ 6 - 0
app/Http/Routes/UserRoute.php

@@ -19,6 +19,7 @@ class UserRoute
             $router->post('/update', 'User\\UserController@update');
             $router->get ('/getSubscribe', 'User\\UserController@getSubscribe');
             $router->get ('/getStat', 'User\\UserController@getStat');
+            $router->post('/transfer', 'User\\UserController@transfer');
             // Order
             $router->post('/order/save', 'User\\OrderController@save');
             $router->post('/order/checkout', 'User\\OrderController@checkout');
@@ -44,11 +45,16 @@ class UserRoute
             $router->post('/ticket/close', 'User\\TicketController@close');
             $router->post('/ticket/save', 'User\\TicketController@save');
             $router->get ('/ticket/fetch', 'User\\TicketController@fetch');
+            $router->post('/ticket/withdraw', 'User\\TicketController@withdraw');
             // Server
             $router->get ('/server/fetch', 'User\\ServerController@fetch');
             $router->get ('/server/log/fetch', 'User\\ServerController@logFetch');
             // Coupon
             $router->post('/coupon/check', 'User\\CouponController@check');
+            // Telegram
+            $router->get ('/telegram/getBotInfo', 'User\\TelegramController@getBotInfo');
+            // Comm
+            $router->get ('/comm/config', 'User\\CommController@config');
         });
     }
 }

+ 43 - 0
app/Jobs/SendTelegramJob.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\TelegramService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class SendTelegramJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+    protected $telegramId;
+    protected $text;
+
+    public $tries = 3;
+    public $timeout = 5;
+
+    /**
+     * Create a new job instance.
+     *
+     * @return void
+     */
+    public function __construct(int $telegramId, string $text)
+    {
+        $this->onQueue('send_telegram');
+        $this->telegramId = $telegramId;
+        $this->text = $text;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        $telegramService = new TelegramService();
+        $telegramService->sendMessage($this->telegramId, $this->text, 'markdown');
+    }
+}

+ 1 - 0
app/Models/ServerLog.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class ServerLog extends Model
 {

+ 48 - 0
app/Services/CouponService.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Coupon;
+use App\Models\Order;
+use Illuminate\Support\Facades\DB;
+
+class CouponService
+{
+    public $order;
+
+    public function __construct($code)
+    {
+        $this->coupon = Coupon::where('code', $code)->first();
+        if (!$this->coupon) {
+            abort(500, '优惠券无效');
+        }
+        if ($this->coupon->limit_use <= 0 && $this->coupon->limit_use !== NULL) {
+            abort(500, '优惠券已无可用次数');
+        }
+        if (time() < $this->coupon->started_at) {
+            abort(500, '优惠券还未到可用时间');
+        }
+        if (time() > $this->coupon->ended_at) {
+            abort(500, '优惠券已过期');
+        }
+    }
+
+    public function use(Order $order)
+    {
+        switch ($this->coupon->type) {
+            case 1:
+                $order->discount_amount = $this->coupon->value;
+                break;
+            case 2:
+                $order->discount_amount = $order->total_amount * ($this->coupon->value / 100);
+                break;
+        }
+        if ($this->coupon->limit_use !== NULL) {
+            $this->coupon->limit_use = $this->coupon->limit_use - 1;
+            if (!$this->coupon->save()) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 7 - 0
app/Services/MailService.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace App\Services;
+
+class MailService
+{
+}

+ 107 - 0
app/Services/OrderService.php

@@ -3,6 +3,8 @@
 namespace App\Services;
 
 use App\Models\Order;
+use App\Models\Plan;
+use App\Models\User;
 use Illuminate\Support\Facades\DB;
 
 class OrderService
@@ -33,4 +35,109 @@ class OrderService
         DB::commit();
         return true;
     }
+
+    public function create()
+    {
+
+    }
+
+    public function setOrderType(User $user)
+    {
+        $order = $this->order;
+        if ($order->cycle === 'reset_price') {
+            $order->type = 4;
+        } else if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id) {
+            if (!(int)config('v2board.plan_change_enable', 1)) abort(500, '目前不允许更改订阅,请联系客服或提交工单操作');
+            $order->type = 3;
+            $this->getSurplusValue($user, $order);
+            if ($order->surplus_amount >= $order->total_amount) {
+                $order->refund_amount = $order->surplus_amount - $order->total_amount;
+                $order->total_amount = 0;
+            } else {
+                $order->total_amount = $order->total_amount - $order->surplus_amount;
+            }
+        } else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
+            $order->type = 2;
+        } else {
+            $order->type = 1;
+        }
+    }
+
+    public function setVipDiscount(User $user)
+    {
+        $order = $this->order;
+        if ($user->discount) {
+            $order->discount_amount = $order->discount_amount + ($order->total_amount * ($user->discount / 100));
+        }
+        $order->total_amount = $order->total_amount - $order->discount_amount;
+    }
+
+    public function setInvite(User $user)
+    {
+        $order = $this->order;
+        if ($user->invite_user_id && $order->total_amount > 0) {
+            $order->invite_user_id = $user->invite_user_id;
+            $commissionFirstTime = (int)config('v2board.commission_first_time_enable', 1);
+            if (!$commissionFirstTime || ($commissionFirstTime && !Order::where('user_id', $user->id)->where('status', 3)->first())) {
+                $inviter = User::find($user->invite_user_id);
+                if ($inviter && $inviter->commission_rate) {
+                    $order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
+                } else {
+                    $order->commission_balance = $order->total_amount * (config('v2board.invite_commission', 10) / 100);
+                }
+            }
+        }
+    }
+
+    private function getSurplusValue(User $user, Order $order)
+    {
+        if ($user->expired_at === NULL) {
+            $this->getSurplusValueByOneTime($user, $order);
+        } else {
+            $this->getSurplusValueByCycle($user, $order);
+        }
+    }
+
+
+    private function getSurplusValueByOneTime(User $user, Order $order)
+    {
+        $plan = Plan::find($user->plan_id);
+        $trafficUnitPrice = $plan->onetime_price / $plan->transfer_enable;
+        if ($user->discount && $trafficUnitPrice) {
+            $trafficUnitPrice = $trafficUnitPrice - ($trafficUnitPrice * $user->discount / 100);
+        }
+        $notUsedTrafficPrice = $plan->transfer_enable - (($user->u + $user->d) / 1073741824);
+        $result = $trafficUnitPrice * $notUsedTrafficPrice;
+        $orderModel = Order::where('user_id', $user->id)->where('cycle', '!=', 'reset_price')->where('status', 3);
+        $order->surplus_amount = $result > 0 ? $result : 0;
+        $order->surplus_order_ids = json_encode(array_map(function ($v) { return $v['id'];}, $orderModel->get()->toArray()));
+    }
+
+    private function getSurplusValueByCycle(User $user, Order $order)
+    {
+        $strToMonth = [
+            'month_price' => 1,
+            'quarter_price' => 3,
+            'half_year_price' => 6,
+            'year_price' => 12,
+            'onetime_price' => 0
+        ];
+        $orderModel = Order::where('user_id', $user->id)
+            ->where('cycle', '!=', 'reset_price')
+            ->where('status', 3);
+        $surplusAmount = 0;
+        foreach ($orderModel->get() as $item) {
+            $surplusMonth = strtotime("+ {$strToMonth[$item->cycle]}month", $item->created_at->format('U'));
+            if (!$surplusMonth) continue;
+            $surplusMonth = ($surplusMonth - time()) / 2678400 / $strToMonth[$item->cycle];
+            if ($surplusMonth > 0) {
+                $surplusAmount = $surplusAmount + ($item['total_amount'] + $item['balance_amount']) * $surplusMonth;
+            }
+        }
+        if (!$surplusAmount) {
+            return;
+        }
+        $order->surplus_amount = $surplusAmount > 0 ? $surplusAmount : 0;
+        $order->surplus_order_ids = json_encode(array_map(function ($v) { return $v['id'];}, $orderModel->get()->toArray()));
+    }
 }

+ 34 - 0
app/Services/ServerService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Models\ServerLog;
 use App\Models\User;
 use App\Models\Server;
 
@@ -40,6 +41,7 @@ class ServerService
             abort(500, '节点不存在');
         }
         $json = json_decode(self::SERVER_CONFIG);
+        $json->log->loglevel = config('v2board.server_log_level', 'none');
         $json->inboundDetour[0]->port = (int)$localPort;
         $json->inbound->port = (int)$server->server_port;
         $json->inbound->streamSettings->network = $server->network;
@@ -55,6 +57,10 @@ class ServerService
     {
         if ($server->dnsSettings) {
             $dns = json_decode($server->dnsSettings);
+            if (isset($dns->servers)) {
+                array_push($dns->servers, '1.1.1.1');
+                array_push($dns->servers, 'localhost');
+            }
             $json->dns = $dns;
             $json->outbound->settings->domainStrategy = 'UseIP';
         }
@@ -92,6 +98,7 @@ class ServerService
             $rules = json_decode($server->ruleSettings);
             // domain
             if (isset($rules->domain) && !empty($rules->domain)) {
+                $rules->domain = array_filter($rules->domain);
                 $domainObj = new \StdClass();
                 $domainObj->type = 'field';
                 $domainObj->domain = $rules->domain;
@@ -100,6 +107,7 @@ class ServerService
             }
             // protocol
             if (isset($rules->protocol) && !empty($rules->protocol)) {
+                $rules->protocol = array_filter($rules->protocol);
                 $protocolObj = new \StdClass();
                 $protocolObj->type = 'field';
                 $protocolObj->protocol = $rules->protocol;
@@ -128,4 +136,30 @@ class ServerService
             $json->inbound->streamSettings->tlsSettings->certificates[0] = $tls;
         }
     }
+
+    public function log(int $userId, int $serverId, int $u, int $d, float $rate)
+    {
+        if (($u + $d) <= 10240) return;
+        $timestamp = strtotime(date('Y-m-d H:0'));
+        $serverLog = ServerLog::where('log_at', '>=', $timestamp)
+            ->where('log_at', '<', $timestamp + 3600)
+            ->where('server_id', $serverId)
+            ->where('user_id', $userId)
+            ->where('rate', $rate)
+            ->first();
+        if ($serverLog) {
+            $serverLog->u = $serverLog->u + $u;
+            $serverLog->d = $serverLog->d + $d;
+            $serverLog->save();
+        } else {
+            $serverLog = new ServerLog();
+            $serverLog->user_id = $userId;
+            $serverLog->server_id = $serverId;
+            $serverLog->u = $u;
+            $serverLog->d = $d;
+            $serverLog->rate = $rate;
+            $serverLog->log_at = $timestamp;
+            $serverLog->save();
+        }
+    }
 }

+ 46 - 0
app/Services/TelegramService.php

@@ -0,0 +1,46 @@
+<?php
+namespace App\Services;
+
+use \Curl\Curl;
+
+class TelegramService {
+    protected $api;
+
+    public function __construct($token = '')
+    {
+        $this->api = 'http://dev.v2board.com/bot' . config('v2board.telegram_bot_token', $token) . '/';
+    }
+
+    public function sendMessage(int $chatId, string $text, string $parseMode = '')
+    {
+        $this->request('sendMessage', [
+            'chat_id' => $chatId,
+            'text' => $text,
+            'parse_mode' => $parseMode
+        ]);
+    }
+
+    public function getMe()
+    {
+        return $this->request('getMe');
+    }
+
+    public function setWebhook(string $url)
+    {
+        return $this->request('setWebhook', [
+            'url' => $url
+        ]);
+    }
+
+    private function request(string $method, array $params = [])
+    {
+        $curl = new Curl();
+        $curl->get($this->api . $method . '?' . http_build_query($params));
+        $response = $curl->response;
+        $curl->close();
+        if (!$response->ok) {
+            abort(500, '来自TG的错误:' . $response->description);
+        }
+        return $response;
+    }
+}

+ 27 - 0
app/Services/UserService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Models\Order;
 use App\Models\User;
 
 class UserService
@@ -63,4 +64,30 @@ class UserService
         }
         return true;
     }
+
+    public function isNotCompleteOrderByUserId(int $userId):bool
+    {
+        $order = Order::whereIn('status', [0, 1])
+            ->where('user_id', $userId)
+            ->first();
+        if (!$order) {
+            return false;
+        }
+        return true;
+    }
+
+    public function trafficFetch(int $u, int $d, int $userId):bool
+    {
+        $user = User::find($userId);
+        if (!$user) {
+            return false;
+        }
+        $user->t = time();
+        $user->u = $user->u + $u;
+        $user->d = $user->d + $d;
+        if (!$user->save()) {
+            return false;
+        }
+        return true;
+    }
 }

+ 18 - 0
app/Utils/Helper.php

@@ -98,4 +98,22 @@ class Helper
         if (!in_array($suffix, $suffixs)) return false;
         return true;
     }
+
+    public static function trafficConvert(int $byte)
+    {
+        $kb = 1024;
+        $mb = 1048576;
+        $gb = 1073741824;
+        if ($byte > $gb) {
+            return round($byte / $gb, 2) . ' GB';
+        } else if ($byte > $mb) {
+            return round($byte / $mb, 2) . ' MB';
+        } else if ($byte > $kb) {
+            return round($byte / $kb, 2) . ' KB';
+        } else if ($byte < 0) {
+            return 0;
+        } else {
+            return round($byte, 2) . ' B';
+        }
+    }
 }

+ 1 - 1
config/app.php

@@ -236,5 +236,5 @@ return [
     | The only modification by laravel config
     |
     */
-    'version' => '1.2.5'
+    'version' => '1.3'
 ];

+ 31 - 14
database/install.sql

@@ -1,4 +1,4 @@
--- Adminer 4.7.3 MySQL dump
+-- Adminer 4.7.6 MySQL dump
 
 SET NAMES utf8;
 SET time_zone = '+00:00';
@@ -54,7 +54,7 @@ CREATE TABLE `v2_mail_log` (
   `email` varchar(64) NOT NULL,
   `subject` varchar(255) NOT NULL,
   `template_name` varchar(255) NOT NULL,
-  `error` varchar(255) DEFAULT NULL,
+  `error` text,
   `created_at` int(11) NOT NULL,
   `updated_at` int(11) NOT NULL,
   PRIMARY KEY (`id`)
@@ -88,7 +88,8 @@ CREATE TABLE `v2_order` (
   `surplus_amount` int(11) DEFAULT NULL COMMENT '剩余价值',
   `refund_amount` int(11) DEFAULT NULL COMMENT '退款金额',
   `balance_amount` int(11) DEFAULT NULL COMMENT '使用余额',
-  `status` tinyint(1) NOT NULL DEFAULT '0',
+  `surplus_order_ids` text COMMENT '折抵订单',
+  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待支付1开通中2已取消3已完成4已折抵',
   `commission_status` tinyint(1) NOT NULL DEFAULT '0',
   `commission_balance` int(11) NOT NULL DEFAULT '0',
   `created_at` int(11) NOT NULL,
@@ -104,13 +105,15 @@ CREATE TABLE `v2_plan` (
   `transfer_enable` int(11) NOT NULL,
   `name` varchar(255) NOT NULL,
   `show` tinyint(1) NOT NULL DEFAULT '0',
+  `sort` int(11) DEFAULT NULL,
   `renew` tinyint(1) NOT NULL DEFAULT '1',
   `content` text,
-  `month_price` int(11) DEFAULT '0',
-  `quarter_price` int(11) DEFAULT '0',
-  `half_year_price` int(11) DEFAULT '0',
-  `year_price` int(11) DEFAULT '0',
+  `month_price` int(11) DEFAULT NULL,
+  `quarter_price` int(11) DEFAULT NULL,
+  `half_year_price` int(11) DEFAULT NULL,
+  `year_price` int(11) DEFAULT NULL,
   `onetime_price` int(11) DEFAULT NULL,
+  `reset_price` int(11) DEFAULT NULL,
   `created_at` int(11) NOT NULL,
   `updated_at` int(11) NOT NULL,
   PRIMARY KEY (`id`)
@@ -137,6 +140,7 @@ CREATE TABLE `v2_server` (
   `ruleSettings` text,
   `dnsSettings` text,
   `show` tinyint(1) NOT NULL DEFAULT '0',
+  `sort` int(11) DEFAULT NULL,
   `created_at` int(11) NOT NULL,
   `updated_at` int(11) NOT NULL,
   PRIMARY KEY (`id`)
@@ -155,16 +159,32 @@ CREATE TABLE `v2_server_group` (
 
 DROP TABLE IF EXISTS `v2_server_log`;
 CREATE TABLE `v2_server_log` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
   `user_id` int(11) NOT NULL,
   `server_id` int(11) NOT NULL,
   `u` varchar(255) NOT NULL,
   `d` varchar(255) NOT NULL,
   `rate` decimal(10,2) NOT NULL,
+  `log_at` int(11) NOT NULL,
   `created_at` int(11) NOT NULL,
-  `updated_at` int(11) NOT NULL
+  `updated_at` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `log_at` (`log_at`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
+DROP TABLE IF EXISTS `v2_server_stat`;
+CREATE TABLE `v2_server_stat` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `server_id` int(11) NOT NULL,
+  `u` varchar(255) NOT NULL,
+  `d` varchar(25) NOT NULL,
+  `created_at` int(11) NOT NULL,
+  `updated_at` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
 DROP TABLE IF EXISTS `v2_ticket`;
 CREATE TABLE `v2_ticket` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -198,21 +218,18 @@ CREATE TABLE `v2_tutorial` (
   `title` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
   `steps` text,
   `show` tinyint(1) NOT NULL DEFAULT '0',
+  `sort` int(11) DEFAULT NULL,
   `created_at` int(11) NOT NULL,
   `updated_at` int(11) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
-INSERT INTO `v2_tutorial` (`id`, `category_id`, `title`, `steps`, `show`, `created_at`, `updated_at`) VALUES
-(1,	1,	'V2rayN',	'[{\"default_area\":\"<div><div>下载 V2rayN 客户端。</div><div>下载完成后解压,解压完成后运行V2rayN</div><div>运行时请右键,以管理员身份运行</div></div>\",\"download_url\":\"/downloads/V2rayN.zip\"},{\"default_area\":\"<div>点击订阅按钮,选择订阅设置点击添加,输入如下内容后点击确定保存</div>\",\"safe_area\":\"<div>备注:<code onclick=\\\"safeAreaCopy(\'{{$app_name}}\')\\\">{{$app_name}}</code></div>\\n<div>地址(url):<code onclick=\\\"safeAreaCopy(\'{{$subscribe_url}}\')\\\">{{$subscribe_url}}</code></div>\",\"img_url\":\"https://i.loli.net/2019/11/21/UkcHNtERTnjLVS8.jpg\"},{\"default_area\":\"<div>点击订阅后,从服务器列表选择服务器</div>\",\"img_url\":\"https://i.loli.net/2019/11/21/BgPGFQ3kCSuIRjJ.jpg\"},{\"default_area\":\"<div>点击参数设置,找到Http代理,选择PAC模式后按确定保存即启动代理。</div>\",\"img_url\":\"https://i.loli.net/2019/11/21/vnVykKEFT8Lzo3f.jpg\"}]',	1,	1577972408,	1577980882),
-(2,	4,	'V2rayNG',	'[{\"default_area\":\"<div>下载 V2rayNG 客户端。</div>\",\"safe_area\":\"\",\"download_url\":\"/downloads/V2rayNG.apk\"},{\"default_area\":\"<div>打开 V2rayNG 点击左上角的菜单图标打开侧边栏,随后点击 订阅设置,点击右上角的➕按钮新增订阅。</div><div>按照下方内容进行填写,填写完毕后点击右上角的☑️按钮。</div>\",\"safe_area\":\"<div>备注:<code onclick=\\\"safeAreaCopy(\'{{$app_name}}\')\\\">{{$app_name}}</code></div>\\n<div>地址(url):<code onclick=\\\"safeAreaCopy(\'{{$subscribe_url}}\')\\\">{{$subscribe_url}}</code></div>\",\"download_url\":\"\",\"img_url\":\"https://i.loli.net/2019/11/21/ghuVkTe6LBqRxSO.jpg\"},{\"default_area\":\"<div>再次从侧边栏进入 设置 页面,点击 路由模式 将其更改为 \\b绕过局域网及大陆地址。</div>\",\"img_url\":\"https://i.loli.net/2019/11/21/Tf1AGoXZuhJrwOq.jpg\"},{\"default_area\":\"<div>随后从侧边栏回到 配置文件 页面,点击右上角的省略号图标选择更新订阅。</div>\",\"img_url\":\"https://i.loli.net/2019/11/21/UtfPShQXupRmB4L.jpg\"},{\"img_url\":\"https://i.loli.net/2019/11/21/ZkbNsSrAg3m5Dny.jpg\",\"default_area\":\"<div>点击选择您需要的节点,点击右下角的V字按钮即可连接。</div>\"}]',	1,	1577972534,	1577981610),
-(3,	2,	'ClashX',	'[{\"default_area\":\"<div>下载 ClashX 客户端,安装后运行。</div>\",\"download_url\":\"/downloads/ClashX.dmg\",\"img_url\":\"https://i.loli.net/2019/11/20/uNGrjl2noCL1f5B.jpg\"},{\"default_area\":\"<div>点击通知栏 ClashX 图标保持选中状态,按快捷键 ⌘+M(订阅快捷键),在弹出的窗口点击添加输入下方信息</div>\",\"safe_area\":\"<div>Url:<code onclick=\\\"safeAreaCopy(\'{{$subscribe_url}}\')\\\">{{$subscribe_url}}</code></div>\\n<div>Config Name:<code onclick=\\\"safeAreaCopy(\'{{$app_name}}\')\\\">{{$app_name}}</code></div>\",\"img_url\":\"https://i.loli.net/2019/11/20/8eB13mRbFuszwxg.jpg\"},{\"default_area\":\"<div>点击通知栏 ClashX 图标保持选中状态,按快捷键 ⌘+S(设置为系统代理快捷键),即连接完成</div>\"}]',	1,	1577979855,	1577981646),
-(4,	3,	'Shadowrocket',	'[{\"default_area\":\"<div>iOS上使用请在iOS浏览器中打开本页</div>\"},{\"default_area\":\"<div>在 App Store 登录本站提供的美区 Apple ID 下载客户端。</div><div>为了保护您的隐私,请勿在手机设置里直接登录,仅在 App Store 登录即可。</div><div>登陆完成后点击下方下载会自动唤起下载。</div>\",\"safe_area\":\"<div>Apple ID:<code onclick=\\\"safeAreaCopy(\'{{$apple_id}}\')\\\">{{$apple_id}}</code></div><div>密码:<code onclick=\\\"safeAreaCopy(\'{{$apple_id_password}}\')\\\">点击复制密码</code></div>\",\"download_url\":\"https://apps.apple.com/us/app/shadowrocket/id932747118\",\"img_url\":\"https://i.loli.net/2019/11/21/5idkjJ61stWgREV.jpg\"},{\"default_area\":\"<div>待客户端安装完成后,点击下方一键订阅按钮会自动唤起并进行订阅</div>\",\"safe_area\":\"\",\"img_url\":\"https://i.loli.net/2019/11/21/ZcqlNMb3eg5Uhxd.jpg\",\"download_url\":\"shadowrocket://add/sub://{{$b64_subscribe_url}}?remark={{$app_name}}\"},{\"default_area\":\"<div>选择节点进行链接,首次链接过程授权窗口请一路允许。</div>\",\"img_url\":\"https://i.loli.net/2019/11/21/9Zdxksr7Ey6hjlm.jpg\"}]',	1,	1577982016,	1577983283);
 
 DROP TABLE IF EXISTS `v2_user`;
 CREATE TABLE `v2_user` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `invite_user_id` int(11) DEFAULT NULL,
+  `telegram_id` bigint(20) DEFAULT NULL,
   `email` varchar(64) NOT NULL,
   `password` varchar(64) NOT NULL,
   `password_algo` char(10) DEFAULT NULL,
@@ -244,4 +261,4 @@ CREATE TABLE `v2_user` (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 
--- 2020-03-30 09:56:24
+-- 2020-05-12 12:31:04

+ 52 - 0
database/update.sql

@@ -204,3 +204,55 @@ ADD `balance_amount` int(11) NULL COMMENT '使用余额' AFTER `refund_amount`;
 ALTER TABLE `v2_server`
 CHANGE `network` `network` text COLLATE 'utf8_general_ci' NOT NULL AFTER `rate`,
 ADD `dnsSettings` text COLLATE 'utf8_general_ci' NULL AFTER `ruleSettings`;
+
+ALTER TABLE `v2_order`
+ADD `surplus_order_ids` text NULL COMMENT '折抵订单' AFTER `balance_amount`;
+
+ALTER TABLE `v2_order`
+CHANGE `status` `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待支付1开通中2已取消3已完成4已折抵' AFTER `surplus_order_ids`;
+
+CREATE TABLE `v2_server_stat` (
+  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+  `server_id` int(11) NOT NULL,
+  `u` varchar(255) NOT NULL,
+  `d` varchar(25) NOT NULL,
+  `created_at` int(11) NOT NULL,
+  `updated_at` int(11) NOT NULL
+);
+
+ALTER TABLE `v2_tutorial`
+ADD `sort` int(11) NULL AFTER `show`;
+
+ALTER TABLE `v2_server`
+ADD `sort` int(11) NULL AFTER `show`;
+
+ALTER TABLE `v2_plan`
+ADD `sort` int(11) NULL AFTER `show`;
+
+ALTER TABLE `v2_plan`
+CHANGE `month_price` `month_price` int(11) NULL AFTER `content`,
+CHANGE `quarter_price` `quarter_price` int(11) NULL AFTER `month_price`,
+CHANGE `half_year_price` `half_year_price` int(11) NULL AFTER `quarter_price`,
+CHANGE `year_price` `year_price` int(11) NULL AFTER `half_year_price`,
+ADD `reset_price` int(11) NULL AFTER `onetime_price`;
+
+ALTER TABLE `v2_server_log`
+ADD `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
+
+ALTER TABLE `v2_server_log`
+ADD `log_at` int(11) NOT NULL AFTER `rate`;
+
+ALTER TABLE `v2_mail_log`
+CHANGE `error` `error` text COLLATE 'utf8_general_ci' NULL AFTER `template_name`;
+
+ALTER TABLE `v2_plan`
+CHANGE `month_price` `month_price` int(11) NULL AFTER `content`,
+CHANGE `quarter_price` `quarter_price` int(11) NULL AFTER `month_price`,
+CHANGE `half_year_price` `half_year_price` int(11) NULL AFTER `quarter_price`,
+CHANGE `year_price` `year_price` int(11) NULL AFTER `half_year_price`;
+
+ALTER TABLE `v2_server_log`
+ADD INDEX log_at (`log_at`);
+
+ALTER TABLE `v2_user`
+ADD `telegram_id` bigint NULL AFTER `invite_user_id`;

+ 1 - 1
pm2.yaml

@@ -1,5 +1,5 @@
 apps:
   - name     : 'V2Board'
-    script   : 'php artisan queue:work --queue=send_email'
+    script   : 'php artisan queue:work --queue=send_email,send_telegram'
     instances: 4
     out_file : './storage/logs/queue/queue.log'

File diff suppressed because it is too large
+ 0 - 0
public/assets/admin/antd.async.js


+ 1 - 1
public/assets/admin/env.example.js

@@ -1,4 +1,4 @@
-window.v2board = {
+window.settings = {
   // 站点标题
   title: 'V2Board',
   // API

File diff suppressed because it is too large
+ 0 - 0
public/assets/admin/umi.css


File diff suppressed because it is too large
+ 0 - 0
public/assets/admin/umi.js


File diff suppressed because it is too large
+ 0 - 0
public/assets/user/antd.chunk.css


+ 1 - 1
public/assets/user/env.example.js

@@ -1,4 +1,4 @@
-window.v2board = {
+window.settings = {
   // 站点标题
   title: 'V2Board',
   // 站点描述

File diff suppressed because it is too large
+ 0 - 0
public/assets/user/umi.css


File diff suppressed because it is too large
+ 0 - 0
public/assets/user/umi.js


+ 1 - 0
resources/rules/.gitignore

@@ -0,0 +1 @@
+custom.clash.yaml

+ 330 - 300
resources/rules/default.clash.yaml

@@ -1,15 +1,42 @@
+port: 7890
+socks-port: 7891
+allow-lan: false
+mode: Rule
+log-level: info
+external-controller: 127.0.0.1:9090
+experimental:
+  ignore-resolve-fail: true
+dns:
+  enable: true
+  ipv6: false
+  enhanced-mode: redir-host
+  nameserver:
+    - 1.2.4.8
+    - 223.5.5.5
+  fallback:
+    - tls://1.0.0.1:853
+    - tls://dns.google:853
+Proxy:
+
+Proxy Group:
+  - { name: "$app_name", type: select, proxies: ["自动选择", "故障转移"] }
+  - { name: "自动选择", type: url-test, proxies: [], url: "http://www.gstatic.com/generate_204", interval: 86400 }
+  - { name: "故障转移", type: fallback, proxies: [], url: "http://www.gstatic.com/generate_204", interval: 7200 }
+
 Rule:
   # Apple
   - DOMAIN,safebrowsing.urlsec.qq.com,DIRECT # 如果您并不信任此服务提供商或防止其下载消耗过多带宽资源,可以进入 Safari 设置,关闭 Fraudulent Website Warning 功能,并使用 REJECT 策略。
   - DOMAIN,safebrowsing.googleapis.com,DIRECT # 如果您并不信任此服务提供商或防止其下载消耗过多带宽资源,可以进入 Safari 设置,关闭 Fraudulent Website Warning 功能,并使用 REJECT 策略。
-  - DOMAIN,ocsp.apple.com,select
-  - DOMAIN-SUFFIX,digicert.com,select
-  - DOMAIN-SUFFIX,entrust.net,select
-  - DOMAIN,ocsp.verisign.net,select
-  - DOMAIN-SUFFIX,apps.apple.com,select
-  - DOMAIN-SUFFIX,itunes.apple.com,select
-  - DOMAIN-SUFFIX,blobstore.apple.com,select
+  - DOMAIN,ocsp.apple.com,$app_name
+  - DOMAIN-SUFFIX,digicert.com,$app_name
+  - DOMAIN-SUFFIX,entrust.net,$app_name
+  - DOMAIN,ocsp.verisign.net,$app_name
+  - DOMAIN-SUFFIX,apps.apple.com,$app_name
+  - DOMAIN,itunes.apple.com,$app_name
+  - DOMAIN-SUFFIX,blobstore.apple.com,$app_name
   - DOMAIN-SUFFIX,music.apple.com,DIRECT
+  - DOMAIN-SUFFIX,mzstatic.com,DIRECT
+  - DOMAIN-SUFFIX,itunes.apple.com,DIRECT
   - DOMAIN-SUFFIX,icloud.com,DIRECT
   - DOMAIN-SUFFIX,icloud-content.com,DIRECT
   - DOMAIN-SUFFIX,me.com,DIRECT
@@ -48,6 +75,7 @@ Rule:
   - DOMAIN-SUFFIX,bdimg.com,DIRECT
   - DOMAIN-SUFFIX,bdstatic.com,DIRECT
   - DOMAIN-SUFFIX,bilibili.com,DIRECT
+  - DOMAIN-SUFFIX,bilivideo.com,DIRECT
   - DOMAIN-SUFFIX,caiyunapp.com,DIRECT
   - DOMAIN-SUFFIX,clouddn.com,DIRECT
   - DOMAIN-SUFFIX,cnbeta.com,DIRECT
@@ -69,6 +97,7 @@ Rule:
   - DOMAIN-SUFFIX,godic.net,DIRECT
   - DOMAIN-SUFFIX,gtimg.com,DIRECT
   - DOMAIN,cdn.hockeyapp.net,DIRECT
+  - DOMAIN-SUFFIX,hdslb.com,DIRECT
   - DOMAIN-SUFFIX,hongxiu.com,DIRECT
   - DOMAIN-SUFFIX,hxcdn.net,DIRECT
   - DOMAIN-SUFFIX,iciba.com,DIRECT
@@ -157,20 +186,20 @@ Rule:
   - DOMAIN-SUFFIX,zoho.com,DIRECT
 
   # 抗 DNS 污染
-  - DOMAIN-KEYWORD,amazon,select
-  - DOMAIN-KEYWORD,google,select
-  - DOMAIN-KEYWORD,gmail,select
-  - DOMAIN-KEYWORD,youtube,select
-  - DOMAIN-KEYWORD,facebook,select
-  - DOMAIN-SUFFIX,fb.me,select
-  - DOMAIN-SUFFIX,fbcdn.net,select
-  - DOMAIN-KEYWORD,twitter,select
-  - DOMAIN-KEYWORD,instagram,select
-  - DOMAIN-KEYWORD,dropbox,select
-  - DOMAIN-SUFFIX,twimg.com,select
-  - DOMAIN-KEYWORD,blogspot,select
-  - DOMAIN-SUFFIX,youtu.be,select
-  - DOMAIN-KEYWORD,whatsapp,select
+  - DOMAIN-KEYWORD,amazon,$app_name
+  - DOMAIN-KEYWORD,google,$app_name
+  - DOMAIN-KEYWORD,gmail,$app_name
+  - DOMAIN-KEYWORD,youtube,$app_name
+  - DOMAIN-KEYWORD,facebook,$app_name
+  - DOMAIN-SUFFIX,fb.me,$app_name
+  - DOMAIN-SUFFIX,fbcdn.net,$app_name
+  - DOMAIN-KEYWORD,twitter,$app_name
+  - DOMAIN-KEYWORD,instagram,$app_name
+  - DOMAIN-KEYWORD,dropbox,$app_name
+  - DOMAIN-SUFFIX,twimg.com,$app_name
+  - DOMAIN-KEYWORD,blogspot,$app_name
+  - DOMAIN-SUFFIX,youtu.be,$app_name
+  - DOMAIN-KEYWORD,whatsapp,$app_name
 
   # 常见广告域名屏蔽
   - DOMAIN-KEYWORD,admarvel,REJECT
@@ -191,6 +220,7 @@ Rule:
   - DOMAIN-KEYWORD,partnerad,REJECT
   - DOMAIN-KEYWORD,pingfore,REJECT
   - DOMAIN-KEYWORD,supersonicads,REJECT
+  - DOMAIN-KEYWORD,tracking,REJECT
   - DOMAIN-KEYWORD,uedas,REJECT
   - DOMAIN-KEYWORD,umeng,REJECT
   - DOMAIN-KEYWORD,usage,REJECT
@@ -198,287 +228,287 @@ Rule:
   - DOMAIN-KEYWORD,zjtoolbar,REJECT
 
   # 国外网站
-  - DOMAIN-SUFFIX,9to5mac.com,select
-  - DOMAIN-SUFFIX,abpchina.org,select
-  - DOMAIN-SUFFIX,adblockplus.org,select
-  - DOMAIN-SUFFIX,adobe.com,select
-  - DOMAIN-SUFFIX,alfredapp.com,select
-  - DOMAIN-SUFFIX,amplitude.com,select
-  - DOMAIN-SUFFIX,ampproject.org,select
-  - DOMAIN-SUFFIX,android.com,select
-  - DOMAIN-SUFFIX,angularjs.org,select
-  - DOMAIN-SUFFIX,aolcdn.com,select
-  - DOMAIN-SUFFIX,apkpure.com,select
-  - DOMAIN-SUFFIX,appledaily.com,select
-  - DOMAIN-SUFFIX,appshopper.com,select
-  - DOMAIN-SUFFIX,appspot.com,select
-  - DOMAIN-SUFFIX,arcgis.com,select
-  - DOMAIN-SUFFIX,archive.org,select
-  - DOMAIN-SUFFIX,armorgames.com,select
-  - DOMAIN-SUFFIX,aspnetcdn.com,select
-  - DOMAIN-SUFFIX,att.com,select
-  - DOMAIN-SUFFIX,awsstatic.com,select
-  - DOMAIN-SUFFIX,azureedge.net,select
-  - DOMAIN-SUFFIX,azurewebsites.net,select
-  - DOMAIN-SUFFIX,bing.com,select
-  - DOMAIN-SUFFIX,bintray.com,select
-  - DOMAIN-SUFFIX,bit.com,select
-  - DOMAIN-SUFFIX,bit.ly,select
-  - DOMAIN-SUFFIX,bitbucket.org,select
-  - DOMAIN-SUFFIX,bjango.com,select
-  - DOMAIN-SUFFIX,bkrtx.com,select
-  - DOMAIN-SUFFIX,blog.com,select
-  - DOMAIN-SUFFIX,blogcdn.com,select
-  - DOMAIN-SUFFIX,blogger.com,select
-  - DOMAIN-SUFFIX,blogsmithmedia.com,select
-  - DOMAIN-SUFFIX,blogspot.com,select
-  - DOMAIN-SUFFIX,blogspot.hk,select
-  - DOMAIN-SUFFIX,bloomberg.com,select
-  - DOMAIN-SUFFIX,box.com,select
-  - DOMAIN-SUFFIX,box.net,select
-  - DOMAIN-SUFFIX,cachefly.net,select
-  - DOMAIN-SUFFIX,chromium.org,select
-  - DOMAIN-SUFFIX,cl.ly,select
-  - DOMAIN-SUFFIX,cloudflare.com,select
-  - DOMAIN-SUFFIX,cloudfront.net,select
-  - DOMAIN-SUFFIX,cloudmagic.com,select
-  - DOMAIN-SUFFIX,cmail19.com,select
-  - DOMAIN-SUFFIX,cnet.com,select
-  - DOMAIN-SUFFIX,cocoapods.org,select
-  - DOMAIN-SUFFIX,comodoca.com,select
-  - DOMAIN-SUFFIX,crashlytics.com,select
-  - DOMAIN-SUFFIX,culturedcode.com,select
-  - DOMAIN-SUFFIX,d.pr,select
-  - DOMAIN-SUFFIX,danilo.to,select
-  - DOMAIN-SUFFIX,dayone.me,select
-  - DOMAIN-SUFFIX,db.tt,select
-  - DOMAIN-SUFFIX,deskconnect.com,select
-  - DOMAIN-SUFFIX,disq.us,select
-  - DOMAIN-SUFFIX,disqus.com,select
-  - DOMAIN-SUFFIX,disquscdn.com,select
-  - DOMAIN-SUFFIX,dnsimple.com,select
-  - DOMAIN-SUFFIX,docker.com,select
-  - DOMAIN-SUFFIX,dribbble.com,select
-  - DOMAIN-SUFFIX,droplr.com,select
-  - DOMAIN-SUFFIX,duckduckgo.com,select
-  - DOMAIN-SUFFIX,dueapp.com,select
-  - DOMAIN-SUFFIX,dytt8.net,select
-  - DOMAIN-SUFFIX,edgecastcdn.net,select
-  - DOMAIN-SUFFIX,edgekey.net,select
-  - DOMAIN-SUFFIX,edgesuite.net,select
-  - DOMAIN-SUFFIX,engadget.com,select
-  - DOMAIN-SUFFIX,entrust.net,select
-  - DOMAIN-SUFFIX,eurekavpt.com,select
-  - DOMAIN-SUFFIX,evernote.com,select
-  - DOMAIN-SUFFIX,fabric.io,select
-  - DOMAIN-SUFFIX,fast.com,select
-  - DOMAIN-SUFFIX,fastly.net,select
-  - DOMAIN-SUFFIX,fc2.com,select
-  - DOMAIN-SUFFIX,feedburner.com,select
-  - DOMAIN-SUFFIX,feedly.com,select
-  - DOMAIN-SUFFIX,feedsportal.com,select
-  - DOMAIN-SUFFIX,fiftythree.com,select
-  - DOMAIN-SUFFIX,firebaseio.com,select
-  - DOMAIN-SUFFIX,flexibits.com,select
-  - DOMAIN-SUFFIX,flickr.com,select
-  - DOMAIN-SUFFIX,flipboard.com,select
-  - DOMAIN-SUFFIX,g.co,select
-  - DOMAIN-SUFFIX,gabia.net,select
-  - DOMAIN-SUFFIX,geni.us,select
-  - DOMAIN-SUFFIX,gfx.ms,select
-  - DOMAIN-SUFFIX,ggpht.com,select
-  - DOMAIN-SUFFIX,ghostnoteapp.com,select
-  - DOMAIN-SUFFIX,git.io,select
-  - DOMAIN-KEYWORD,github,select
-  - DOMAIN-SUFFIX,globalsign.com,select
-  - DOMAIN-SUFFIX,gmodules.com,select
-  - DOMAIN-SUFFIX,godaddy.com,select
-  - DOMAIN-SUFFIX,golang.org,select
-  - DOMAIN-SUFFIX,gongm.in,select
-  - DOMAIN-SUFFIX,goo.gl,select
-  - DOMAIN-SUFFIX,goodreaders.com,select
-  - DOMAIN-SUFFIX,goodreads.com,select
-  - DOMAIN-SUFFIX,gravatar.com,select
-  - DOMAIN-SUFFIX,gstatic.com,select
-  - DOMAIN-SUFFIX,gvt0.com,select
-  - DOMAIN-SUFFIX,hockeyapp.net,select
-  - DOMAIN-SUFFIX,hotmail.com,select
-  - DOMAIN-SUFFIX,icons8.com,select
-  - DOMAIN-SUFFIX,ifixit.com,select
-  - DOMAIN-SUFFIX,ift.tt,select
-  - DOMAIN-SUFFIX,ifttt.com,select
-  - DOMAIN-SUFFIX,iherb.com,select
-  - DOMAIN-SUFFIX,imageshack.us,select
-  - DOMAIN-SUFFIX,img.ly,select
-  - DOMAIN-SUFFIX,imgur.com,select
-  - DOMAIN-SUFFIX,imore.com,select
-  - DOMAIN-SUFFIX,instapaper.com,select
-  - DOMAIN-SUFFIX,ipn.li,select
-  - DOMAIN-SUFFIX,is.gd,select
-  - DOMAIN-SUFFIX,issuu.com,select
-  - DOMAIN-SUFFIX,itgonglun.com,select
-  - DOMAIN-SUFFIX,itun.es,select
-  - DOMAIN-SUFFIX,ixquick.com,select
-  - DOMAIN-SUFFIX,j.mp,select
-  - DOMAIN-SUFFIX,js.revsci.net,select
-  - DOMAIN-SUFFIX,jshint.com,select
-  - DOMAIN-SUFFIX,jtvnw.net,select
-  - DOMAIN-SUFFIX,justgetflux.com,select
-  - DOMAIN-SUFFIX,kat.cr,select
-  - DOMAIN-SUFFIX,klip.me,select
-  - DOMAIN-SUFFIX,libsyn.com,select
-  - DOMAIN-SUFFIX,linode.com,select
-  - DOMAIN-SUFFIX,lithium.com,select
-  - DOMAIN-SUFFIX,littlehj.com,select
-  - DOMAIN-SUFFIX,live.com,select
-  - DOMAIN-SUFFIX,live.net,select
-  - DOMAIN-SUFFIX,livefilestore.com,select
-  - DOMAIN-SUFFIX,llnwd.net,select
-  - DOMAIN-SUFFIX,macid.co,select
-  - DOMAIN-SUFFIX,macromedia.com,select
-  - DOMAIN-SUFFIX,macrumors.com,select
-  - DOMAIN-SUFFIX,mashable.com,select
-  - DOMAIN-SUFFIX,mathjax.org,select
-  - DOMAIN-SUFFIX,medium.com,select
-  - DOMAIN-SUFFIX,mega.co.nz,select
-  - DOMAIN-SUFFIX,mega.nz,select
-  - DOMAIN-SUFFIX,megaupload.com,select
-  - DOMAIN-SUFFIX,microsofttranslator.com,select
-  - DOMAIN-SUFFIX,mindnode.com,select
-  - DOMAIN-SUFFIX,mobile01.com,select
-  - DOMAIN-SUFFIX,modmyi.com,select
-  - DOMAIN-SUFFIX,msedge.net,select
-  - DOMAIN-SUFFIX,myfontastic.com,select
-  - DOMAIN-SUFFIX,name.com,select
-  - DOMAIN-SUFFIX,nextmedia.com,select
-  - DOMAIN-SUFFIX,nsstatic.net,select
-  - DOMAIN-SUFFIX,nssurge.com,select
-  - DOMAIN-SUFFIX,nyt.com,select
-  - DOMAIN-SUFFIX,nytimes.com,select
-  - DOMAIN-SUFFIX,omnigroup.com,select
-  - DOMAIN-SUFFIX,onedrive.com,select
-  - DOMAIN-SUFFIX,onenote.com,select
-  - DOMAIN-SUFFIX,ooyala.com,select
-  - DOMAIN-SUFFIX,openvpn.net,select
-  - DOMAIN-SUFFIX,openwrt.org,select
-  - DOMAIN-SUFFIX,orkut.com,select
-  - DOMAIN-SUFFIX,osxdaily.com,select
-  - DOMAIN-SUFFIX,outlook.com,select
-  - DOMAIN-SUFFIX,ow.ly,select
-  - DOMAIN-SUFFIX,paddleapi.com,select
-  - DOMAIN-SUFFIX,parallels.com,select
-  - DOMAIN-SUFFIX,parse.com,select
-  - DOMAIN-SUFFIX,pdfexpert.com,select
-  - DOMAIN-SUFFIX,periscope.tv,select
-  - DOMAIN-SUFFIX,pinboard.in,select
-  - DOMAIN-SUFFIX,pinterest.com,select
-  - DOMAIN-SUFFIX,pixelmator.com,select
-  - DOMAIN-SUFFIX,pixiv.net,select
-  - DOMAIN-SUFFIX,playpcesor.com,select
-  - DOMAIN-SUFFIX,playstation.com,select
-  - DOMAIN-SUFFIX,playstation.com.hk,select
-  - DOMAIN-SUFFIX,playstation.net,select
-  - DOMAIN-SUFFIX,playstationnetwork.com,select
-  - DOMAIN-SUFFIX,pushwoosh.com,select
-  - DOMAIN-SUFFIX,rime.im,select
-  - DOMAIN-SUFFIX,servebom.com,select
-  - DOMAIN-SUFFIX,sfx.ms,select
-  - DOMAIN-SUFFIX,shadowsocks.org,select
-  - DOMAIN-SUFFIX,sharethis.com,select
-  - DOMAIN-SUFFIX,shazam.com,select
-  - DOMAIN-SUFFIX,skype.com,select
-  - DOMAIN-SUFFIX,smartdnsselect.com,select
-  - DOMAIN-SUFFIX,smartmailcloud.com,select
-  - DOMAIN-SUFFIX,sndcdn.com,select
-  - DOMAIN-SUFFIX,sony.com,select
-  - DOMAIN-SUFFIX,soundcloud.com,select
-  - DOMAIN-SUFFIX,sourceforge.net,select
-  - DOMAIN-SUFFIX,spotify.com,select
-  - DOMAIN-SUFFIX,squarespace.com,select
-  - DOMAIN-SUFFIX,sstatic.net,select
-  - DOMAIN-SUFFIX,st.luluku.pw,select
-  - DOMAIN-SUFFIX,stackoverflow.com,select
-  - DOMAIN-SUFFIX,startpage.com,select
-  - DOMAIN-SUFFIX,staticflickr.com,select
-  - DOMAIN-SUFFIX,steamcommunity.com,select
-  - DOMAIN-SUFFIX,symauth.com,select
-  - DOMAIN-SUFFIX,symcb.com,select
-  - DOMAIN-SUFFIX,symcd.com,select
-  - DOMAIN-SUFFIX,tapbots.com,select
-  - DOMAIN-SUFFIX,tapbots.net,select
-  - DOMAIN-SUFFIX,tdesktop.com,select
-  - DOMAIN-SUFFIX,techcrunch.com,select
-  - DOMAIN-SUFFIX,techsmith.com,select
-  - DOMAIN-SUFFIX,thepiratebay.org,select
-  - DOMAIN-SUFFIX,theverge.com,select
-  - DOMAIN-SUFFIX,time.com,select
-  - DOMAIN-SUFFIX,timeinc.net,select
-  - DOMAIN-SUFFIX,tiny.cc,select
-  - DOMAIN-SUFFIX,tinypic.com,select
-  - DOMAIN-SUFFIX,tmblr.co,select
-  - DOMAIN-SUFFIX,todoist.com,select
-  - DOMAIN-SUFFIX,trello.com,select
-  - DOMAIN-SUFFIX,trustasiassl.com,select
-  - DOMAIN-SUFFIX,tumblr.co,select
-  - DOMAIN-SUFFIX,tumblr.com,select
-  - DOMAIN-SUFFIX,tweetdeck.com,select
-  - DOMAIN-SUFFIX,tweetmarker.net,select
-  - DOMAIN-SUFFIX,twitch.tv,select
-  - DOMAIN-SUFFIX,txmblr.com,select
-  - DOMAIN-SUFFIX,typekit.net,select
-  - DOMAIN-SUFFIX,ubertags.com,select
-  - DOMAIN-SUFFIX,ublock.org,select
-  - DOMAIN-SUFFIX,ubnt.com,select
-  - DOMAIN-SUFFIX,ulyssesapp.com,select
-  - DOMAIN-SUFFIX,urchin.com,select
-  - DOMAIN-SUFFIX,usertrust.com,select
-  - DOMAIN-SUFFIX,v.gd,select
-  - DOMAIN-SUFFIX,v2ex.com,select
-  - DOMAIN-SUFFIX,vimeo.com,select
-  - DOMAIN-SUFFIX,vimeocdn.com,select
-  - DOMAIN-SUFFIX,vine.co,select
-  - DOMAIN-SUFFIX,vivaldi.com,select
-  - DOMAIN-SUFFIX,vox-cdn.com,select
-  - DOMAIN-SUFFIX,vsco.co,select
-  - DOMAIN-SUFFIX,vultr.com,select
-  - DOMAIN-SUFFIX,w.org,select
-  - DOMAIN-SUFFIX,w3schools.com,select
-  - DOMAIN-SUFFIX,webtype.com,select
-  - DOMAIN-SUFFIX,wikiwand.com,select
-  - DOMAIN-SUFFIX,wikileaks.org,select
-  - DOMAIN-SUFFIX,wikimedia.org,select
-  - DOMAIN-SUFFIX,wikipedia.com,select
-  - DOMAIN-SUFFIX,wikipedia.org,select
-  - DOMAIN-SUFFIX,windows.com,select
-  - DOMAIN-SUFFIX,windows.net,select
-  - DOMAIN-SUFFIX,wire.com,select
-  - DOMAIN-SUFFIX,wordpress.com,select
-  - DOMAIN-SUFFIX,workflowy.com,select
-  - DOMAIN-SUFFIX,wp.com,select
-  - DOMAIN-SUFFIX,wsj.com,select
-  - DOMAIN-SUFFIX,wsj.net,select
-  - DOMAIN-SUFFIX,xda-developers.com,select
-  - DOMAIN-SUFFIX,xeeno.com,select
-  - DOMAIN-SUFFIX,xiti.com,select
-  - DOMAIN-SUFFIX,yahoo.com,select
-  - DOMAIN-SUFFIX,yimg.com,select
-  - DOMAIN-SUFFIX,ying.com,select
-  - DOMAIN-SUFFIX,yoyo.org,select
-  - DOMAIN-SUFFIX,ytimg.com,select
+  - DOMAIN-SUFFIX,9to5mac.com,$app_name
+  - DOMAIN-SUFFIX,abpchina.org,$app_name
+  - DOMAIN-SUFFIX,adblockplus.org,$app_name
+  - DOMAIN-SUFFIX,adobe.com,$app_name
+  - DOMAIN-SUFFIX,alfredapp.com,$app_name
+  - DOMAIN-SUFFIX,amplitude.com,$app_name
+  - DOMAIN-SUFFIX,ampproject.org,$app_name
+  - DOMAIN-SUFFIX,android.com,$app_name
+  - DOMAIN-SUFFIX,angularjs.org,$app_name
+  - DOMAIN-SUFFIX,aolcdn.com,$app_name
+  - DOMAIN-SUFFIX,apkpure.com,$app_name
+  - DOMAIN-SUFFIX,appledaily.com,$app_name
+  - DOMAIN-SUFFIX,appshopper.com,$app_name
+  - DOMAIN-SUFFIX,appspot.com,$app_name
+  - DOMAIN-SUFFIX,arcgis.com,$app_name
+  - DOMAIN-SUFFIX,archive.org,$app_name
+  - DOMAIN-SUFFIX,armorgames.com,$app_name
+  - DOMAIN-SUFFIX,aspnetcdn.com,$app_name
+  - DOMAIN-SUFFIX,att.com,$app_name
+  - DOMAIN-SUFFIX,awsstatic.com,$app_name
+  - DOMAIN-SUFFIX,azureedge.net,$app_name
+  - DOMAIN-SUFFIX,azurewebsites.net,$app_name
+  - DOMAIN-SUFFIX,bing.com,$app_name
+  - DOMAIN-SUFFIX,bintray.com,$app_name
+  - DOMAIN-SUFFIX,bit.com,$app_name
+  - DOMAIN-SUFFIX,bit.ly,$app_name
+  - DOMAIN-SUFFIX,bitbucket.org,$app_name
+  - DOMAIN-SUFFIX,bjango.com,$app_name
+  - DOMAIN-SUFFIX,bkrtx.com,$app_name
+  - DOMAIN-SUFFIX,blog.com,$app_name
+  - DOMAIN-SUFFIX,blogcdn.com,$app_name
+  - DOMAIN-SUFFIX,blogger.com,$app_name
+  - DOMAIN-SUFFIX,blogsmithmedia.com,$app_name
+  - DOMAIN-SUFFIX,blogspot.com,$app_name
+  - DOMAIN-SUFFIX,blogspot.hk,$app_name
+  - DOMAIN-SUFFIX,bloomberg.com,$app_name
+  - DOMAIN-SUFFIX,box.com,$app_name
+  - DOMAIN-SUFFIX,box.net,$app_name
+  - DOMAIN-SUFFIX,cachefly.net,$app_name
+  - DOMAIN-SUFFIX,chromium.org,$app_name
+  - DOMAIN-SUFFIX,cl.ly,$app_name
+  - DOMAIN-SUFFIX,cloudflare.com,$app_name
+  - DOMAIN-SUFFIX,cloudfront.net,$app_name
+  - DOMAIN-SUFFIX,cloudmagic.com,$app_name
+  - DOMAIN-SUFFIX,cmail19.com,$app_name
+  - DOMAIN-SUFFIX,cnet.com,$app_name
+  - DOMAIN-SUFFIX,cocoapods.org,$app_name
+  - DOMAIN-SUFFIX,comodoca.com,$app_name
+  - DOMAIN-SUFFIX,crashlytics.com,$app_name
+  - DOMAIN-SUFFIX,culturedcode.com,$app_name
+  - DOMAIN-SUFFIX,d.pr,$app_name
+  - DOMAIN-SUFFIX,danilo.to,$app_name
+  - DOMAIN-SUFFIX,dayone.me,$app_name
+  - DOMAIN-SUFFIX,db.tt,$app_name
+  - DOMAIN-SUFFIX,deskconnect.com,$app_name
+  - DOMAIN-SUFFIX,disq.us,$app_name
+  - DOMAIN-SUFFIX,disqus.com,$app_name
+  - DOMAIN-SUFFIX,disquscdn.com,$app_name
+  - DOMAIN-SUFFIX,dnsimple.com,$app_name
+  - DOMAIN-SUFFIX,docker.com,$app_name
+  - DOMAIN-SUFFIX,dribbble.com,$app_name
+  - DOMAIN-SUFFIX,droplr.com,$app_name
+  - DOMAIN-SUFFIX,duckduckgo.com,$app_name
+  - DOMAIN-SUFFIX,dueapp.com,$app_name
+  - DOMAIN-SUFFIX,dytt8.net,$app_name
+  - DOMAIN-SUFFIX,edgecastcdn.net,$app_name
+  - DOMAIN-SUFFIX,edgekey.net,$app_name
+  - DOMAIN-SUFFIX,edgesuite.net,$app_name
+  - DOMAIN-SUFFIX,engadget.com,$app_name
+  - DOMAIN-SUFFIX,entrust.net,$app_name
+  - DOMAIN-SUFFIX,eurekavpt.com,$app_name
+  - DOMAIN-SUFFIX,evernote.com,$app_name
+  - DOMAIN-SUFFIX,fabric.io,$app_name
+  - DOMAIN-SUFFIX,fast.com,$app_name
+  - DOMAIN-SUFFIX,fastly.net,$app_name
+  - DOMAIN-SUFFIX,fc2.com,$app_name
+  - DOMAIN-SUFFIX,feedburner.com,$app_name
+  - DOMAIN-SUFFIX,feedly.com,$app_name
+  - DOMAIN-SUFFIX,feedsportal.com,$app_name
+  - DOMAIN-SUFFIX,fiftythree.com,$app_name
+  - DOMAIN-SUFFIX,firebaseio.com,$app_name
+  - DOMAIN-SUFFIX,flexibits.com,$app_name
+  - DOMAIN-SUFFIX,flickr.com,$app_name
+  - DOMAIN-SUFFIX,flipboard.com,$app_name
+  - DOMAIN-SUFFIX,g.co,$app_name
+  - DOMAIN-SUFFIX,gabia.net,$app_name
+  - DOMAIN-SUFFIX,geni.us,$app_name
+  - DOMAIN-SUFFIX,gfx.ms,$app_name
+  - DOMAIN-SUFFIX,ggpht.com,$app_name
+  - DOMAIN-SUFFIX,ghostnoteapp.com,$app_name
+  - DOMAIN-SUFFIX,git.io,$app_name
+  - DOMAIN-KEYWORD,github,$app_name
+  - DOMAIN-SUFFIX,globalsign.com,$app_name
+  - DOMAIN-SUFFIX,gmodules.com,$app_name
+  - DOMAIN-SUFFIX,godaddy.com,$app_name
+  - DOMAIN-SUFFIX,golang.org,$app_name
+  - DOMAIN-SUFFIX,gongm.in,$app_name
+  - DOMAIN-SUFFIX,goo.gl,$app_name
+  - DOMAIN-SUFFIX,goodreaders.com,$app_name
+  - DOMAIN-SUFFIX,goodreads.com,$app_name
+  - DOMAIN-SUFFIX,gravatar.com,$app_name
+  - DOMAIN-SUFFIX,gstatic.com,$app_name
+  - DOMAIN-SUFFIX,gvt0.com,$app_name
+  - DOMAIN-SUFFIX,hockeyapp.net,$app_name
+  - DOMAIN-SUFFIX,hotmail.com,$app_name
+  - DOMAIN-SUFFIX,icons8.com,$app_name
+  - DOMAIN-SUFFIX,ifixit.com,$app_name
+  - DOMAIN-SUFFIX,ift.tt,$app_name
+  - DOMAIN-SUFFIX,ifttt.com,$app_name
+  - DOMAIN-SUFFIX,iherb.com,$app_name
+  - DOMAIN-SUFFIX,imageshack.us,$app_name
+  - DOMAIN-SUFFIX,img.ly,$app_name
+  - DOMAIN-SUFFIX,imgur.com,$app_name
+  - DOMAIN-SUFFIX,imore.com,$app_name
+  - DOMAIN-SUFFIX,instapaper.com,$app_name
+  - DOMAIN-SUFFIX,ipn.li,$app_name
+  - DOMAIN-SUFFIX,is.gd,$app_name
+  - DOMAIN-SUFFIX,issuu.com,$app_name
+  - DOMAIN-SUFFIX,itgonglun.com,$app_name
+  - DOMAIN-SUFFIX,itun.es,$app_name
+  - DOMAIN-SUFFIX,ixquick.com,$app_name
+  - DOMAIN-SUFFIX,j.mp,$app_name
+  - DOMAIN-SUFFIX,js.revsci.net,$app_name
+  - DOMAIN-SUFFIX,jshint.com,$app_name
+  - DOMAIN-SUFFIX,jtvnw.net,$app_name
+  - DOMAIN-SUFFIX,justgetflux.com,$app_name
+  - DOMAIN-SUFFIX,kat.cr,$app_name
+  - DOMAIN-SUFFIX,klip.me,$app_name
+  - DOMAIN-SUFFIX,libsyn.com,$app_name
+  - DOMAIN-SUFFIX,linode.com,$app_name
+  - DOMAIN-SUFFIX,lithium.com,$app_name
+  - DOMAIN-SUFFIX,littlehj.com,$app_name
+  - DOMAIN-SUFFIX,live.com,$app_name
+  - DOMAIN-SUFFIX,live.net,$app_name
+  - DOMAIN-SUFFIX,livefilestore.com,$app_name
+  - DOMAIN-SUFFIX,llnwd.net,$app_name
+  - DOMAIN-SUFFIX,macid.co,$app_name
+  - DOMAIN-SUFFIX,macromedia.com,$app_name
+  - DOMAIN-SUFFIX,macrumors.com,$app_name
+  - DOMAIN-SUFFIX,mashable.com,$app_name
+  - DOMAIN-SUFFIX,mathjax.org,$app_name
+  - DOMAIN-SUFFIX,medium.com,$app_name
+  - DOMAIN-SUFFIX,mega.co.nz,$app_name
+  - DOMAIN-SUFFIX,mega.nz,$app_name
+  - DOMAIN-SUFFIX,megaupload.com,$app_name
+  - DOMAIN-SUFFIX,microsofttranslator.com,$app_name
+  - DOMAIN-SUFFIX,mindnode.com,$app_name
+  - DOMAIN-SUFFIX,mobile01.com,$app_name
+  - DOMAIN-SUFFIX,modmyi.com,$app_name
+  - DOMAIN-SUFFIX,msedge.net,$app_name
+  - DOMAIN-SUFFIX,myfontastic.com,$app_name
+  - DOMAIN-SUFFIX,name.com,$app_name
+  - DOMAIN-SUFFIX,nextmedia.com,$app_name
+  - DOMAIN-SUFFIX,nsstatic.net,$app_name
+  - DOMAIN-SUFFIX,nssurge.com,$app_name
+  - DOMAIN-SUFFIX,nyt.com,$app_name
+  - DOMAIN-SUFFIX,nytimes.com,$app_name
+  - DOMAIN-SUFFIX,omnigroup.com,$app_name
+  - DOMAIN-SUFFIX,onedrive.com,$app_name
+  - DOMAIN-SUFFIX,onenote.com,$app_name
+  - DOMAIN-SUFFIX,ooyala.com,$app_name
+  - DOMAIN-SUFFIX,openvpn.net,$app_name
+  - DOMAIN-SUFFIX,openwrt.org,$app_name
+  - DOMAIN-SUFFIX,orkut.com,$app_name
+  - DOMAIN-SUFFIX,osxdaily.com,$app_name
+  - DOMAIN-SUFFIX,outlook.com,$app_name
+  - DOMAIN-SUFFIX,ow.ly,$app_name
+  - DOMAIN-SUFFIX,paddleapi.com,$app_name
+  - DOMAIN-SUFFIX,parallels.com,$app_name
+  - DOMAIN-SUFFIX,parse.com,$app_name
+  - DOMAIN-SUFFIX,pdfexpert.com,$app_name
+  - DOMAIN-SUFFIX,periscope.tv,$app_name
+  - DOMAIN-SUFFIX,pinboard.in,$app_name
+  - DOMAIN-SUFFIX,pinterest.com,$app_name
+  - DOMAIN-SUFFIX,pixelmator.com,$app_name
+  - DOMAIN-SUFFIX,pixiv.net,$app_name
+  - DOMAIN-SUFFIX,playpcesor.com,$app_name
+  - DOMAIN-SUFFIX,playstation.com,$app_name
+  - DOMAIN-SUFFIX,playstation.com.hk,$app_name
+  - DOMAIN-SUFFIX,playstation.net,$app_name
+  - DOMAIN-SUFFIX,playstationnetwork.com,$app_name
+  - DOMAIN-SUFFIX,pushwoosh.com,$app_name
+  - DOMAIN-SUFFIX,rime.im,$app_name
+  - DOMAIN-SUFFIX,servebom.com,$app_name
+  - DOMAIN-SUFFIX,sfx.ms,$app_name
+  - DOMAIN-SUFFIX,shadowsocks.org,$app_name
+  - DOMAIN-SUFFIX,sharethis.com,$app_name
+  - DOMAIN-SUFFIX,shazam.com,$app_name
+  - DOMAIN-SUFFIX,skype.com,$app_name
+  - DOMAIN-SUFFIX,smartdns$app_name.com,$app_name
+  - DOMAIN-SUFFIX,smartmailcloud.com,$app_name
+  - DOMAIN-SUFFIX,sndcdn.com,$app_name
+  - DOMAIN-SUFFIX,sony.com,$app_name
+  - DOMAIN-SUFFIX,soundcloud.com,$app_name
+  - DOMAIN-SUFFIX,sourceforge.net,$app_name
+  - DOMAIN-SUFFIX,spotify.com,$app_name
+  - DOMAIN-SUFFIX,squarespace.com,$app_name
+  - DOMAIN-SUFFIX,sstatic.net,$app_name
+  - DOMAIN-SUFFIX,st.luluku.pw,$app_name
+  - DOMAIN-SUFFIX,stackoverflow.com,$app_name
+  - DOMAIN-SUFFIX,startpage.com,$app_name
+  - DOMAIN-SUFFIX,staticflickr.com,$app_name
+  - DOMAIN-SUFFIX,steamcommunity.com,$app_name
+  - DOMAIN-SUFFIX,symauth.com,$app_name
+  - DOMAIN-SUFFIX,symcb.com,$app_name
+  - DOMAIN-SUFFIX,symcd.com,$app_name
+  - DOMAIN-SUFFIX,tapbots.com,$app_name
+  - DOMAIN-SUFFIX,tapbots.net,$app_name
+  - DOMAIN-SUFFIX,tdesktop.com,$app_name
+  - DOMAIN-SUFFIX,techcrunch.com,$app_name
+  - DOMAIN-SUFFIX,techsmith.com,$app_name
+  - DOMAIN-SUFFIX,thepiratebay.org,$app_name
+  - DOMAIN-SUFFIX,theverge.com,$app_name
+  - DOMAIN-SUFFIX,time.com,$app_name
+  - DOMAIN-SUFFIX,timeinc.net,$app_name
+  - DOMAIN-SUFFIX,tiny.cc,$app_name
+  - DOMAIN-SUFFIX,tinypic.com,$app_name
+  - DOMAIN-SUFFIX,tmblr.co,$app_name
+  - DOMAIN-SUFFIX,todoist.com,$app_name
+  - DOMAIN-SUFFIX,trello.com,$app_name
+  - DOMAIN-SUFFIX,trustasiassl.com,$app_name
+  - DOMAIN-SUFFIX,tumblr.co,$app_name
+  - DOMAIN-SUFFIX,tumblr.com,$app_name
+  - DOMAIN-SUFFIX,tweetdeck.com,$app_name
+  - DOMAIN-SUFFIX,tweetmarker.net,$app_name
+  - DOMAIN-SUFFIX,twitch.tv,$app_name
+  - DOMAIN-SUFFIX,txmblr.com,$app_name
+  - DOMAIN-SUFFIX,typekit.net,$app_name
+  - DOMAIN-SUFFIX,ubertags.com,$app_name
+  - DOMAIN-SUFFIX,ublock.org,$app_name
+  - DOMAIN-SUFFIX,ubnt.com,$app_name
+  - DOMAIN-SUFFIX,ulyssesapp.com,$app_name
+  - DOMAIN-SUFFIX,urchin.com,$app_name
+  - DOMAIN-SUFFIX,usertrust.com,$app_name
+  - DOMAIN-SUFFIX,v.gd,$app_name
+  - DOMAIN-SUFFIX,v2ex.com,$app_name
+  - DOMAIN-SUFFIX,vimeo.com,$app_name
+  - DOMAIN-SUFFIX,vimeocdn.com,$app_name
+  - DOMAIN-SUFFIX,vine.co,$app_name
+  - DOMAIN-SUFFIX,vivaldi.com,$app_name
+  - DOMAIN-SUFFIX,vox-cdn.com,$app_name
+  - DOMAIN-SUFFIX,vsco.co,$app_name
+  - DOMAIN-SUFFIX,vultr.com,$app_name
+  - DOMAIN-SUFFIX,w.org,$app_name
+  - DOMAIN-SUFFIX,w3schools.com,$app_name
+  - DOMAIN-SUFFIX,webtype.com,$app_name
+  - DOMAIN-SUFFIX,wikiwand.com,$app_name
+  - DOMAIN-SUFFIX,wikileaks.org,$app_name
+  - DOMAIN-SUFFIX,wikimedia.org,$app_name
+  - DOMAIN-SUFFIX,wikipedia.com,$app_name
+  - DOMAIN-SUFFIX,wikipedia.org,$app_name
+  - DOMAIN-SUFFIX,windows.com,$app_name
+  - DOMAIN-SUFFIX,windows.net,$app_name
+  - DOMAIN-SUFFIX,wire.com,$app_name
+  - DOMAIN-SUFFIX,wordpress.com,$app_name
+  - DOMAIN-SUFFIX,workflowy.com,$app_name
+  - DOMAIN-SUFFIX,wp.com,$app_name
+  - DOMAIN-SUFFIX,wsj.com,$app_name
+  - DOMAIN-SUFFIX,wsj.net,$app_name
+  - DOMAIN-SUFFIX,xda-developers.com,$app_name
+  - DOMAIN-SUFFIX,xeeno.com,$app_name
+  - DOMAIN-SUFFIX,xiti.com,$app_name
+  - DOMAIN-SUFFIX,yahoo.com,$app_name
+  - DOMAIN-SUFFIX,yimg.com,$app_name
+  - DOMAIN-SUFFIX,ying.com,$app_name
+  - DOMAIN-SUFFIX,yoyo.org,$app_name
+  - DOMAIN-SUFFIX,ytimg.com,$app_name
 
   # Telegram
-  - DOMAIN-SUFFIX,telegra.ph,select
-  - DOMAIN-SUFFIX,telegram.org,select
+  - DOMAIN-SUFFIX,telegra.ph,$app_name
+  - DOMAIN-SUFFIX,telegram.org,$app_name
 
-  - IP-CIDR,91.108.4.0/22,select,no-resolve
-  - IP-CIDR,91.108.8.0/22,select,no-resolve
-  - IP-CIDR,91.108.12.0/22,select,no-resolve
-  - IP-CIDR,91.108.16.0/22,select,no-resolve
-  - IP-CIDR,91.108.56.0/22,select,no-resolve
-  - IP-CIDR,149.154.160.0/22,select,no-resolve
-  - IP-CIDR,149.154.164.0/22,select,no-resolve
-  - IP-CIDR,149.154.168.0/22,select,no-resolve
-  - IP-CIDR,149.154.172.0/22,select,no-resolve
+  - IP-CIDR,91.108.4.0/22,$app_name,no-resolve
+  - IP-CIDR,91.108.8.0/22,$app_name,no-resolve
+  - IP-CIDR,91.108.12.0/22,$app_name,no-resolve
+  - IP-CIDR,91.108.16.0/22,$app_name,no-resolve
+  - IP-CIDR,91.108.56.0/22,$app_name,no-resolve
+  - IP-CIDR,149.154.160.0/22,$app_name,no-resolve
+  - IP-CIDR,149.154.164.0/22,$app_name,no-resolve
+  - IP-CIDR,149.154.168.0/22,$app_name,no-resolve
+  - IP-CIDR,149.154.172.0/22,$app_name,no-resolve
 
   # LAN
   - DOMAIN-SUFFIX,local,DIRECT
@@ -491,4 +521,4 @@ Rule:
 
   # 最终规则
   - GEOIP,CN,DIRECT
-  - MATCH,select
+  - MATCH,$app_name

+ 524 - 0
resources/rules/default.surfboard.conf

@@ -0,0 +1,524 @@
+#!MANAGED-CONFIG $subs_link interval=43200 strict=true
+
+[General]
+loglevel = notify
+interface = 127.0.0.1
+skip-proxy = localhost, *.local, 0.0.0.0/8, 10.0.0.0/8, 17.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32
+ipv6 = false
+dns-server = 1.2.4.8, 114.114.114.114, 223.5.5.5, 8.8.8.8, system
+exclude-simple-hostnames = true
+enhanced-mode-by-rule = true
+
+# Surfboard 的服务器和策略组配置方式与 Surge 类似, 可以参考 Surge 的规则配置手册: https://manual.nssurge.com/
+
+[Proxy]
+$proxies
+
+[Proxy Group]
+Proxy = select, auto, fallback, $proxy_group
+auto = url-test, $proxy_group, url=http://www.gstatic.com/generate_204, interval=43200
+fallback = fallback, $proxy_group, url=http://www.gstatic.com/generate_204, interval=43200
+
+[Rule]
+# 自定义规则
+## 您可以在这里插入自定义规则
+
+# Google Service
+DOMAIN-SUFFIX,googleapis.cn,Proxy
+DOMAIN-KEYWORD,ampproject,Proxy
+DOMAIN-SUFFIX,android.com,Proxy
+DOMAIN-SUFFIX,g.co,Proxy
+DOMAIN-SUFFIX,ggpht.com,Proxy
+DOMAIN-SUFFIX,goo.gl,Proxy
+DOMAIN-KEYWORD,gstatic,Proxy
+DOMAIN-SUFFIX,gvt0.com,Proxy
+DOMAIN-SUFFIX,gvt1.com,Proxy
+DOMAIN-SUFFIX,gvt2.com,Proxy
+DOMAIN-SUFFIX,gvt3.com,Proxy
+DOMAIN-SUFFIX,appspot.com,Proxy,force-remote-dns
+DOMAIN-KEYWORD,google,Proxy,force-remote-dns
+
+# Apple
+DOMAIN,ocsp.apple.com,Proxy
+DOMAIN-SUFFIX,digicert.com,Proxy
+DOMAIN-SUFFIX,entrust.net,Proxy
+DOMAIN,ocsp.verisign.net,Proxy
+DOMAIN,itunes.apple.com,Proxy,force-remote-dns
+DOMAIN-SUFFIX,apps.apple.com,Proxy,force-remote-dns
+DOMAIN-SUFFIX,blobstore.apple.com,Proxy
+DOMAIN-SUFFIX,music.apple.com,DIRECT,force-remote-dns
+DOMAIN-SUFFIX,mzstatic.com,DIRECT
+DOMAIN-SUFFIX,itunes.apple.com,DIRECT
+DOMAIN-SUFFIX,icloud.com,DIRECT
+DOMAIN-SUFFIX,icloud-content.com,DIRECT
+DOMAIN-SUFFIX,me.com,DIRECT
+DOMAIN-SUFFIX,akadns.net,DIRECT
+DOMAIN-SUFFIX,aaplimg.com,DIRECT
+DOMAIN-SUFFIX,cdn-apple.com,DIRECT
+DOMAIN-SUFFIX,apple.com,DIRECT
+DOMAIN-SUFFIX,apple-cloudkit.com,DIRECT
+
+# 国内网站
+DOMAIN-SUFFIX,cn,DIRECT
+DOMAIN-KEYWORD,-cn,DIRECT
+
+DOMAIN-SUFFIX,126.com,DIRECT
+DOMAIN-SUFFIX,126.net,DIRECT
+DOMAIN-SUFFIX,127.net,DIRECT
+DOMAIN-SUFFIX,163.com,DIRECT
+DOMAIN-SUFFIX,360buyimg.com,DIRECT
+DOMAIN-SUFFIX,36kr.com,DIRECT
+DOMAIN-SUFFIX,acfun.tv,DIRECT
+DOMAIN-SUFFIX,air-matters.com,DIRECT
+DOMAIN-SUFFIX,aixifan.com,DIRECT
+DOMAIN-SUFFIX,akamaized.net,DIRECT
+DOMAIN-KEYWORD,alicdn,DIRECT
+DOMAIN-KEYWORD,alipay,DIRECT
+DOMAIN-KEYWORD,taobao,DIRECT
+DOMAIN-SUFFIX,amap.com,DIRECT
+DOMAIN-SUFFIX,autonavi.com,DIRECT
+DOMAIN-KEYWORD,baidu,DIRECT
+DOMAIN-SUFFIX,bdimg.com,DIRECT
+DOMAIN-SUFFIX,bdstatic.com,DIRECT
+DOMAIN-SUFFIX,bilibili.com,DIRECT
+DOMAIN-SUFFIX,bilivideo.com,DIRECT
+DOMAIN-SUFFIX,caiyunapp.com,DIRECT
+DOMAIN-SUFFIX,clouddn.com,DIRECT
+DOMAIN-SUFFIX,cnbeta.com,DIRECT
+DOMAIN-SUFFIX,cnbetacdn.com,DIRECT
+DOMAIN-SUFFIX,cootekservice.com,DIRECT
+DOMAIN-SUFFIX,csdn.net,DIRECT
+DOMAIN-SUFFIX,ctrip.com,DIRECT
+DOMAIN-SUFFIX,dgtle.com,DIRECT
+DOMAIN-SUFFIX,dianping.com,DIRECT
+DOMAIN-SUFFIX,douban.com,DIRECT
+DOMAIN-SUFFIX,doubanio.com,DIRECT
+DOMAIN-SUFFIX,duokan.com,DIRECT
+DOMAIN-SUFFIX,easou.com,DIRECT
+DOMAIN-SUFFIX,ele.me,DIRECT
+DOMAIN-SUFFIX,feng.com,DIRECT
+DOMAIN-SUFFIX,fir.im,DIRECT
+DOMAIN-SUFFIX,frdic.com,DIRECT
+DOMAIN-SUFFIX,g-cores.com,DIRECT
+DOMAIN-SUFFIX,godic.net,DIRECT
+DOMAIN-SUFFIX,gtimg.com,DIRECT
+DOMAIN,cdn.hockeyapp.net,DIRECT
+DOMAIN-SUFFIX,hongxiu.com,DIRECT
+DOMAIN-SUFFIX,hxcdn.net,DIRECT
+DOMAIN-SUFFIX,iciba.com,DIRECT
+DOMAIN-SUFFIX,ifeng.com,DIRECT
+DOMAIN-SUFFIX,ifengimg.com,DIRECT
+DOMAIN-SUFFIX,ipip.net,DIRECT
+DOMAIN-SUFFIX,iqiyi.com,DIRECT
+DOMAIN-SUFFIX,jd.com,DIRECT
+DOMAIN-SUFFIX,jianshu.com,DIRECT
+DOMAIN-SUFFIX,knewone.com,DIRECT
+DOMAIN-SUFFIX,le.com,DIRECT
+DOMAIN-SUFFIX,lecloud.com,DIRECT
+DOMAIN-SUFFIX,lemicp.com,DIRECT
+DOMAIN-SUFFIX,licdn.com,DIRECT
+DOMAIN-SUFFIX,linkedin.com,DIRECT
+DOMAIN-SUFFIX,luoo.net,DIRECT
+DOMAIN-SUFFIX,meituan.com,DIRECT
+DOMAIN-SUFFIX,meituan.net,DIRECT
+DOMAIN-SUFFIX,mi.com,DIRECT
+DOMAIN-SUFFIX,miaopai.com,DIRECT
+DOMAIN-SUFFIX,microsoft.com,DIRECT
+DOMAIN-SUFFIX,microsoftonline.com,DIRECT
+DOMAIN-SUFFIX,miui.com,DIRECT
+DOMAIN-SUFFIX,miwifi.com,DIRECT
+DOMAIN-SUFFIX,mob.com,DIRECT
+DOMAIN-SUFFIX,netease.com,DIRECT
+DOMAIN-SUFFIX,office.com,DIRECT
+DOMAIN-KEYWORD,officecdn,DIRECT
+DOMAIN-SUFFIX,office365.com,DIRECT
+DOMAIN-SUFFIX,oschina.net,DIRECT
+DOMAIN-SUFFIX,ppsimg.com,DIRECT
+DOMAIN-SUFFIX,pstatp.com,DIRECT
+DOMAIN-SUFFIX,qcloud.com,DIRECT
+DOMAIN-SUFFIX,qdaily.com,DIRECT
+DOMAIN-SUFFIX,qdmm.com,DIRECT
+DOMAIN-SUFFIX,qhimg.com,DIRECT
+DOMAIN-SUFFIX,qhres.com,DIRECT
+DOMAIN-SUFFIX,qidian.com,DIRECT
+DOMAIN-SUFFIX,qihucdn.com,DIRECT
+DOMAIN-SUFFIX,qiniu.com,DIRECT
+DOMAIN-SUFFIX,qiniucdn.com,DIRECT
+DOMAIN-SUFFIX,qiyipic.com,DIRECT
+DOMAIN-SUFFIX,qq.com,DIRECT
+DOMAIN-SUFFIX,qqurl.com,DIRECT
+DOMAIN-SUFFIX,rarbg.to,DIRECT
+DOMAIN-SUFFIX,ruguoapp.com,DIRECT
+DOMAIN-SUFFIX,segmentfault.com,DIRECT
+DOMAIN-SUFFIX,sinaapp.com,DIRECT
+DOMAIN-SUFFIX,smzdm.com,DIRECT
+DOMAIN-SUFFIX,snapdrop.net,DIRECT
+DOMAIN-SUFFIX,sogou.com,DIRECT
+DOMAIN-SUFFIX,sogoucdn.com,DIRECT
+DOMAIN-SUFFIX,sohu.com,DIRECT
+DOMAIN-SUFFIX,soku.com,DIRECT
+DOMAIN-SUFFIX,speedtest.net,DIRECT
+DOMAIN-SUFFIX,sspai.com,DIRECT
+DOMAIN-SUFFIX,suning.com,DIRECT
+DOMAIN-SUFFIX,taobao.com,DIRECT
+DOMAIN-SUFFIX,tencent.com,DIRECT
+DOMAIN-SUFFIX,tenpay.com,DIRECT
+DOMAIN-SUFFIX,tianyancha.com,DIRECT
+DOMAIN-SUFFIX,tmall.com,DIRECT
+DOMAIN-SUFFIX,tudou.com,DIRECT
+DOMAIN-SUFFIX,umetrip.com,DIRECT
+DOMAIN-SUFFIX,upaiyun.com,DIRECT
+DOMAIN-SUFFIX,upyun.com,DIRECT
+DOMAIN-SUFFIX,veryzhun.com,DIRECT
+DOMAIN-SUFFIX,weather.com,DIRECT
+DOMAIN-SUFFIX,weibo.com,DIRECT
+DOMAIN-SUFFIX,xiami.com,DIRECT
+DOMAIN-SUFFIX,xiami.net,DIRECT
+DOMAIN-SUFFIX,xiaomicp.com,DIRECT
+DOMAIN-SUFFIX,ximalaya.com,DIRECT
+DOMAIN-SUFFIX,xmcdn.com,DIRECT
+DOMAIN-SUFFIX,xunlei.com,DIRECT
+DOMAIN-SUFFIX,yhd.com,DIRECT
+DOMAIN-SUFFIX,yihaodianimg.com,DIRECT
+DOMAIN-SUFFIX,yinxiang.com,DIRECT
+DOMAIN-SUFFIX,ykimg.com,DIRECT
+DOMAIN-SUFFIX,youdao.com,DIRECT
+DOMAIN-SUFFIX,youku.com,DIRECT
+DOMAIN-SUFFIX,zealer.com,DIRECT
+DOMAIN-SUFFIX,zhihu.com,DIRECT
+DOMAIN-SUFFIX,zhimg.com,DIRECT
+DOMAIN-SUFFIX,zimuzu.tv,DIRECT
+DOMAIN-SUFFIX,zoho.com,DIRECT
+
+# 抗 DNS 污染 
+DOMAIN-KEYWORD,amazon,Proxy
+DOMAIN-KEYWORD,gmail,Proxy
+DOMAIN-KEYWORD,youtube,Proxy
+DOMAIN-KEYWORD,facebook,Proxy
+DOMAIN-SUFFIX,fb.me,Proxy
+DOMAIN-SUFFIX,fbcdn.net,Proxy
+DOMAIN-KEYWORD,twitter,Proxy
+DOMAIN-KEYWORD,instagram,Proxy
+DOMAIN-KEYWORD,dropbox,Proxy
+DOMAIN-SUFFIX,twimg.com,Proxy
+DOMAIN-KEYWORD,blogspot,Proxy
+DOMAIN-SUFFIX,youtu.be,Proxy
+DOMAIN-KEYWORD,whatsapp,Proxy
+
+# 常见广告域名关键词屏蔽
+DOMAIN-KEYWORD,admarvel,REJECT
+DOMAIN-KEYWORD,admaster,REJECT
+DOMAIN-KEYWORD,adsage,REJECT
+DOMAIN-KEYWORD,adsmogo,REJECT
+DOMAIN-KEYWORD,adsrvmedia,REJECT
+DOMAIN-KEYWORD,adwords,REJECT
+DOMAIN-KEYWORD,adservice,REJECT
+DOMAIN-KEYWORD,domob,REJECT
+DOMAIN-KEYWORD,duomeng,REJECT
+DOMAIN-KEYWORD,dwtrack,REJECT
+DOMAIN-KEYWORD,guanggao,REJECT
+DOMAIN-KEYWORD,lianmeng,REJECT
+DOMAIN-SUFFIX,mmstat.com,REJECT
+DOMAIN-KEYWORD,omgmta,REJECT
+DOMAIN-KEYWORD,openx,REJECT
+DOMAIN-KEYWORD,partnerad,REJECT
+DOMAIN-KEYWORD,pingfore,REJECT
+DOMAIN-KEYWORD,supersonicads,REJECT
+DOMAIN-KEYWORD,uedas,REJECT
+DOMAIN-KEYWORD,umeng,REJECT
+DOMAIN-KEYWORD,usage,REJECT
+DOMAIN-KEYWORD,wlmonitor,REJECT
+DOMAIN-KEYWORD,zjtoolbar,REJECT
+
+# 国外网站
+DOMAIN-SUFFIX,9to5mac.com,Proxy
+DOMAIN-SUFFIX,abpchina.org,Proxy
+DOMAIN-SUFFIX,adblockplus.org,Proxy
+DOMAIN-SUFFIX,adobe.com,Proxy
+DOMAIN-SUFFIX,alfredapp.com,Proxy
+DOMAIN-SUFFIX,amplitude.com,Proxy
+DOMAIN-SUFFIX,ampproject.org,Proxy
+DOMAIN-SUFFIX,android.com,Proxy
+DOMAIN-SUFFIX,angularjs.org,Proxy
+DOMAIN-SUFFIX,aolcdn.com,Proxy
+DOMAIN-SUFFIX,apkpure.com,Proxy
+DOMAIN-SUFFIX,appledaily.com,Proxy
+DOMAIN-SUFFIX,appshopper.com,Proxy
+DOMAIN-SUFFIX,appspot.com,Proxy
+DOMAIN-SUFFIX,arcgis.com,Proxy
+DOMAIN-SUFFIX,archive.org,Proxy
+DOMAIN-SUFFIX,armorgames.com,Proxy
+DOMAIN-SUFFIX,aspnetcdn.com,Proxy
+DOMAIN-SUFFIX,att.com,Proxy
+DOMAIN-SUFFIX,awsstatic.com,Proxy
+DOMAIN-SUFFIX,azureedge.net,Proxy
+DOMAIN-SUFFIX,azurewebsites.net,Proxy
+DOMAIN-SUFFIX,bing.com,Proxy
+DOMAIN-SUFFIX,bintray.com,Proxy
+DOMAIN-SUFFIX,bit.com,Proxy
+DOMAIN-SUFFIX,bit.ly,Proxy
+DOMAIN-SUFFIX,bitbucket.org,Proxy
+DOMAIN-SUFFIX,bjango.com,Proxy
+DOMAIN-SUFFIX,bkrtx.com,Proxy
+DOMAIN-SUFFIX,blog.com,Proxy
+DOMAIN-SUFFIX,blogcdn.com,Proxy
+DOMAIN-SUFFIX,blogger.com,Proxy
+DOMAIN-SUFFIX,blogsmithmedia.com,Proxy
+DOMAIN-SUFFIX,blogspot.com,Proxy
+DOMAIN-SUFFIX,blogspot.hk,Proxy
+DOMAIN-SUFFIX,bloomberg.com,Proxy
+DOMAIN-SUFFIX,box.com,Proxy
+DOMAIN-SUFFIX,box.net,Proxy
+DOMAIN-SUFFIX,cachefly.net,Proxy
+DOMAIN-SUFFIX,chromium.org,Proxy
+DOMAIN-SUFFIX,cl.ly,Proxy
+DOMAIN-SUFFIX,cloudflare.com,Proxy
+DOMAIN-SUFFIX,cloudfront.net,Proxy
+DOMAIN-SUFFIX,cloudmagic.com,Proxy
+DOMAIN-SUFFIX,cmail19.com,Proxy
+DOMAIN-SUFFIX,cnet.com,Proxy
+DOMAIN-SUFFIX,cocoapods.org,Proxy
+DOMAIN-SUFFIX,comodoca.com,Proxy
+DOMAIN-SUFFIX,crashlytics.com,Proxy
+DOMAIN-SUFFIX,culturedcode.com,Proxy
+DOMAIN-SUFFIX,d.pr,Proxy
+DOMAIN-SUFFIX,danilo.to,Proxy
+DOMAIN-SUFFIX,dayone.me,Proxy
+DOMAIN-SUFFIX,db.tt,Proxy
+DOMAIN-SUFFIX,deskconnect.com,Proxy
+DOMAIN-SUFFIX,disq.us,Proxy
+DOMAIN-SUFFIX,disqus.com,Proxy
+DOMAIN-SUFFIX,disquscdn.com,Proxy
+DOMAIN-SUFFIX,dnsimple.com,Proxy
+DOMAIN-SUFFIX,docker.com,Proxy
+DOMAIN-SUFFIX,dribbble.com,Proxy
+DOMAIN-SUFFIX,droplr.com,Proxy
+DOMAIN-SUFFIX,duckduckgo.com,Proxy
+DOMAIN-SUFFIX,dueapp.com,Proxy
+DOMAIN-SUFFIX,dytt8.net,Proxy
+DOMAIN-SUFFIX,edgecastcdn.net,Proxy
+DOMAIN-SUFFIX,edgekey.net,Proxy
+DOMAIN-SUFFIX,edgesuite.net,Proxy
+DOMAIN-SUFFIX,engadget.com,Proxy
+DOMAIN-SUFFIX,entrust.net,Proxy
+DOMAIN-SUFFIX,eurekavpt.com,Proxy
+DOMAIN-SUFFIX,evernote.com,Proxy
+DOMAIN-SUFFIX,fabric.io,Proxy
+DOMAIN-SUFFIX,fast.com,Proxy
+DOMAIN-SUFFIX,fastly.net,Proxy
+DOMAIN-SUFFIX,fc2.com,Proxy
+DOMAIN-SUFFIX,feedburner.com,Proxy
+DOMAIN-SUFFIX,feedly.com,Proxy
+DOMAIN-SUFFIX,feedsportal.com,Proxy
+DOMAIN-SUFFIX,fiftythree.com,Proxy
+DOMAIN-SUFFIX,firebaseio.com,Proxy
+DOMAIN-SUFFIX,flexibits.com,Proxy
+DOMAIN-SUFFIX,flickr.com,Proxy
+DOMAIN-SUFFIX,flipboard.com,Proxy
+DOMAIN-SUFFIX,g.co,Proxy
+DOMAIN-SUFFIX,gabia.net,Proxy
+DOMAIN-SUFFIX,geni.us,Proxy
+DOMAIN-SUFFIX,gfx.ms,Proxy
+DOMAIN-SUFFIX,ggpht.com,Proxy
+DOMAIN-SUFFIX,ghostnoteapp.com,Proxy
+DOMAIN-SUFFIX,git.io,Proxy
+DOMAIN-KEYWORD,github,Proxy
+DOMAIN-SUFFIX,globalsign.com,Proxy
+DOMAIN-SUFFIX,gmodules.com,Proxy
+DOMAIN-SUFFIX,godaddy.com,Proxy
+DOMAIN-SUFFIX,golang.org,Proxy
+DOMAIN-SUFFIX,gongm.in,Proxy
+DOMAIN-SUFFIX,goodreaders.com,Proxy
+DOMAIN-SUFFIX,goodreads.com,Proxy
+DOMAIN-SUFFIX,gravatar.com,Proxy
+DOMAIN-SUFFIX,hockeyapp.net,Proxy
+DOMAIN-SUFFIX,hotmail.com,Proxy
+DOMAIN-SUFFIX,icons8.com,Proxy
+DOMAIN-SUFFIX,ifixit.com,Proxy
+DOMAIN-SUFFIX,ift.tt,Proxy
+DOMAIN-SUFFIX,ifttt.com,Proxy
+DOMAIN-SUFFIX,iherb.com,Proxy
+DOMAIN-SUFFIX,imageshack.us,Proxy
+DOMAIN-SUFFIX,img.ly,Proxy
+DOMAIN-SUFFIX,imgur.com,Proxy
+DOMAIN-SUFFIX,imore.com,Proxy
+DOMAIN-SUFFIX,instapaper.com,Proxy
+DOMAIN-SUFFIX,ipn.li,Proxy
+DOMAIN-SUFFIX,is.gd,Proxy
+DOMAIN-SUFFIX,issuu.com,Proxy
+DOMAIN-SUFFIX,itgonglun.com,Proxy
+DOMAIN-SUFFIX,itun.es,Proxy
+DOMAIN-SUFFIX,ixquick.com,Proxy
+DOMAIN-SUFFIX,j.mp,Proxy
+DOMAIN-SUFFIX,js.revsci.net,Proxy
+DOMAIN-SUFFIX,jshint.com,Proxy
+DOMAIN-SUFFIX,jtvnw.net,Proxy
+DOMAIN-SUFFIX,justgetflux.com,Proxy
+DOMAIN-SUFFIX,kat.cr,Proxy
+DOMAIN-SUFFIX,klip.me,Proxy
+DOMAIN-SUFFIX,libsyn.com,Proxy
+DOMAIN-SUFFIX,linode.com,Proxy
+DOMAIN-SUFFIX,lithium.com,Proxy
+DOMAIN-SUFFIX,littlehj.com,Proxy
+DOMAIN-SUFFIX,live.com,Proxy
+DOMAIN-SUFFIX,live.net,Proxy
+DOMAIN-SUFFIX,livefilestore.com,Proxy
+DOMAIN-SUFFIX,llnwd.net,Proxy
+DOMAIN-SUFFIX,macid.co,Proxy
+DOMAIN-SUFFIX,macromedia.com,Proxy
+DOMAIN-SUFFIX,macrumors.com,Proxy
+DOMAIN-SUFFIX,mashable.com,Proxy
+DOMAIN-SUFFIX,mathjax.org,Proxy
+DOMAIN-SUFFIX,medium.com,Proxy
+DOMAIN-SUFFIX,mega.co.nz,Proxy
+DOMAIN-SUFFIX,mega.nz,Proxy
+DOMAIN-SUFFIX,megaupload.com,Proxy
+DOMAIN-SUFFIX,microsofttranslator.com,Proxy
+DOMAIN-SUFFIX,mindnode.com,Proxy
+DOMAIN-SUFFIX,mobile01.com,Proxy
+DOMAIN-SUFFIX,modmyi.com,Proxy
+DOMAIN-SUFFIX,msedge.net,Proxy
+DOMAIN-SUFFIX,myfontastic.com,Proxy
+DOMAIN-SUFFIX,name.com,Proxy
+DOMAIN-SUFFIX,nextmedia.com,Proxy
+DOMAIN-SUFFIX,nsstatic.net,Proxy
+DOMAIN-SUFFIX,nssurge.com,Proxy
+DOMAIN-SUFFIX,nyt.com,Proxy
+DOMAIN-SUFFIX,nytimes.com,Proxy
+DOMAIN-SUFFIX,omnigroup.com,Proxy
+DOMAIN-SUFFIX,onedrive.com,Proxy
+DOMAIN-SUFFIX,onenote.com,Proxy
+DOMAIN-SUFFIX,ooyala.com,Proxy
+DOMAIN-SUFFIX,openvpn.net,Proxy
+DOMAIN-SUFFIX,openwrt.org,Proxy
+DOMAIN-SUFFIX,orkut.com,Proxy
+DOMAIN-SUFFIX,osxdaily.com,Proxy
+DOMAIN-SUFFIX,outlook.com,Proxy
+DOMAIN-SUFFIX,ow.ly,Proxy
+DOMAIN-SUFFIX,paddleapi.com,Proxy
+DOMAIN-SUFFIX,parallels.com,Proxy
+DOMAIN-SUFFIX,parse.com,Proxy
+DOMAIN-SUFFIX,pdfexpert.com,Proxy
+DOMAIN-SUFFIX,periscope.tv,Proxy
+DOMAIN-SUFFIX,pinboard.in,Proxy
+DOMAIN-SUFFIX,pinterest.com,Proxy
+DOMAIN-SUFFIX,pixelmator.com,Proxy
+DOMAIN-SUFFIX,pixiv.net,Proxy
+DOMAIN-SUFFIX,playpcesor.com,Proxy
+DOMAIN-SUFFIX,playstation.com,Proxy
+DOMAIN-SUFFIX,playstation.com.hk,Proxy
+DOMAIN-SUFFIX,playstation.net,Proxy
+DOMAIN-SUFFIX,playstationnetwork.com,Proxy
+DOMAIN-SUFFIX,pushwoosh.com,Proxy
+DOMAIN-SUFFIX,rime.im,Proxy
+DOMAIN-SUFFIX,servebom.com,Proxy
+DOMAIN-SUFFIX,sfx.ms,Proxy
+DOMAIN-SUFFIX,shadowsocks.org,Proxy
+DOMAIN-SUFFIX,sharethis.com,Proxy
+DOMAIN-SUFFIX,shazam.com,Proxy
+DOMAIN-SUFFIX,skype.com,Proxy
+DOMAIN-SUFFIX,smartdnsProxy.com,Proxy
+DOMAIN-SUFFIX,smartmailcloud.com,Proxy
+DOMAIN-SUFFIX,sndcdn.com,Proxy
+DOMAIN-SUFFIX,sony.com,Proxy
+DOMAIN-SUFFIX,soundcloud.com,Proxy
+DOMAIN-SUFFIX,sourceforge.net,Proxy
+DOMAIN-SUFFIX,spotify.com,Proxy
+DOMAIN-SUFFIX,squarespace.com,Proxy
+DOMAIN-SUFFIX,sstatic.net,Proxy
+DOMAIN-SUFFIX,st.luluku.pw,Proxy
+DOMAIN-SUFFIX,stackoverflow.com,Proxy
+DOMAIN-SUFFIX,startpage.com,Proxy
+DOMAIN-SUFFIX,staticflickr.com,Proxy
+DOMAIN-SUFFIX,steamcommunity.com,Proxy
+DOMAIN-SUFFIX,symauth.com,Proxy
+DOMAIN-SUFFIX,symcb.com,Proxy
+DOMAIN-SUFFIX,symcd.com,Proxy
+DOMAIN-SUFFIX,tapbots.com,Proxy
+DOMAIN-SUFFIX,tapbots.net,Proxy
+DOMAIN-SUFFIX,tdesktop.com,Proxy
+DOMAIN-SUFFIX,techcrunch.com,Proxy
+DOMAIN-SUFFIX,techsmith.com,Proxy
+DOMAIN-SUFFIX,thepiratebay.org,Proxy
+DOMAIN-SUFFIX,theverge.com,Proxy
+DOMAIN-SUFFIX,time.com,Proxy
+DOMAIN-SUFFIX,timeinc.net,Proxy
+DOMAIN-SUFFIX,tiny.cc,Proxy
+DOMAIN-SUFFIX,tinypic.com,Proxy
+DOMAIN-SUFFIX,tmblr.co,Proxy
+DOMAIN-SUFFIX,todoist.com,Proxy
+DOMAIN-SUFFIX,trello.com,Proxy
+DOMAIN-SUFFIX,trustasiassl.com,Proxy
+DOMAIN-SUFFIX,tumblr.co,Proxy
+DOMAIN-SUFFIX,tumblr.com,Proxy
+DOMAIN-SUFFIX,tweetdeck.com,Proxy
+DOMAIN-SUFFIX,tweetmarker.net,Proxy
+DOMAIN-SUFFIX,twitch.tv,Proxy
+DOMAIN-SUFFIX,txmblr.com,Proxy
+DOMAIN-SUFFIX,typekit.net,Proxy
+DOMAIN-SUFFIX,ubertags.com,Proxy
+DOMAIN-SUFFIX,ublock.org,Proxy
+DOMAIN-SUFFIX,ubnt.com,Proxy
+DOMAIN-SUFFIX,ulyssesapp.com,Proxy
+DOMAIN-SUFFIX,urchin.com,Proxy
+DOMAIN-SUFFIX,usertrust.com,Proxy
+DOMAIN-SUFFIX,v.gd,Proxy
+DOMAIN-SUFFIX,v2ex.com,Proxy
+DOMAIN-SUFFIX,vimeo.com,Proxy
+DOMAIN-SUFFIX,vimeocdn.com,Proxy
+DOMAIN-SUFFIX,vine.co,Proxy
+DOMAIN-SUFFIX,vivaldi.com,Proxy
+DOMAIN-SUFFIX,vox-cdn.com,Proxy
+DOMAIN-SUFFIX,vsco.co,Proxy
+DOMAIN-SUFFIX,vultr.com,Proxy
+DOMAIN-SUFFIX,w.org,Proxy
+DOMAIN-SUFFIX,w3schools.com,Proxy
+DOMAIN-SUFFIX,webtype.com,Proxy
+DOMAIN-SUFFIX,wikiwand.com,Proxy
+DOMAIN-SUFFIX,wikileaks.org,Proxy
+DOMAIN-SUFFIX,wikimedia.org,Proxy
+DOMAIN-SUFFIX,wikipedia.com,Proxy
+DOMAIN-SUFFIX,wikipedia.org,Proxy
+DOMAIN-SUFFIX,windows.com,Proxy
+DOMAIN-SUFFIX,windows.net,Proxy
+DOMAIN-SUFFIX,wire.com,Proxy
+DOMAIN-SUFFIX,wordpress.com,Proxy
+DOMAIN-SUFFIX,workflowy.com,Proxy
+DOMAIN-SUFFIX,wp.com,Proxy
+DOMAIN-SUFFIX,wsj.com,Proxy
+DOMAIN-SUFFIX,wsj.net,Proxy
+DOMAIN-SUFFIX,xda-developers.com,Proxy
+DOMAIN-SUFFIX,xeeno.com,Proxy
+DOMAIN-SUFFIX,xiti.com,Proxy
+DOMAIN-SUFFIX,yahoo.com,Proxy
+DOMAIN-SUFFIX,yimg.com,Proxy
+DOMAIN-SUFFIX,ying.com,Proxy
+DOMAIN-SUFFIX,yoyo.org,Proxy
+DOMAIN-SUFFIX,ytimg.com,Proxy
+
+# Telegram
+DOMAIN-SUFFIX,telegra.ph,Proxy
+DOMAIN-SUFFIX,telegram.org,Proxy
+
+IP-CIDR,91.108.4.0/22,Proxy
+IP-CIDR,91.108.8.0/22,Proxy
+IP-CIDR,91.108.12.0/22,Proxy
+IP-CIDR,91.108.16.0/22,Proxy
+IP-CIDR,91.108.56.0/22,Proxy
+IP-CIDR,149.154.160.0/22,Proxy
+IP-CIDR,149.154.164.0/22,Proxy
+IP-CIDR,149.154.168.0/22,Proxy
+IP-CIDR,149.154.172.0/22,Proxy
+
+# LAN
+DOMAIN-SUFFIX,local,DIRECT
+IP-CIDR,127.0.0.0/8,DIRECT
+IP-CIDR,172.16.0.0/12,DIRECT
+IP-CIDR,192.168.0.0/16,DIRECT
+IP-CIDR,10.0.0.0/8,DIRECT
+IP-CIDR,17.0.0.0/8,DIRECT
+IP-CIDR,100.64.0.0/10,DIRECT
+
+# 最终规则
+GEOIP,CN,DIRECT
+FINAL,Proxy

+ 50 - 803
resources/rules/default.surge.conf

@@ -1,817 +1,64 @@
-#!MANAGED-CONFIG {subs_link} interval=43200 strict=true
+#!MANAGED-CONFIG $subs_link interval=43200 strict=true
 
 [General]
 loglevel = notify
-interface = 127.0.0.1
-skip-proxy = localhost, *.local, 0.0.0.0/8, 10.0.0.0/8, 17.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32
-ipv6 = false
 dns-server = 1.2.4.8, 114.114.114.114, 223.5.5.5, 8.8.8.8, system
-exclude-simple-hostnames = true
-enhanced-mode-by-rule = true
-
-[Proxy]
-{proxies}
-
-[Proxy Group]
-Proxy = select, auto, fallback, {proxy_group}
-auto = url-test, {proxy_group}, url=http://www.gstatic.com/generate_204, interval=600
-fallback = fallback, {proxy_group}, url=http://www.gstatic.com/generate_204, interval=600
-
-[Host]
-localhost = 127.0.0.1
-store.steampowered.com = 23.50.18.229
-autodraw.com = 216.239.38.21
-www.w3schools.com = 192.229.173.207
-
-[Rule]
-# REJECT Start
-
-// Tracking-Protection
-DOMAIN-SUFFIX,google-analytics.com,REJECT
-DOMAIN-SUFFIX,adjust.com,REJECT
-DOMAIN-SUFFIX,appsflyer.com,REJECT
-DOMAIN-SUFFIX,umengcloud.com,REJECT
-DOMAIN-SUFFIX,umeng.com,REJECT
-DOMAIN-SUFFIX,cnzz.com,REJECT
-DOMAIN-SUFFIX,growingio.com,REJECT
-DOMAIN-SUFFIX,inmobi.com,REJECT
-DOMAIN-SUFFIX,inmobi.cn,REJECT
-DOMAIN-SUFFIX,lnk0.com,REJECT
-DOMAIN-SUFFIX,serving-sys.com,REJECT
-DOMAIN,cdn.segment.com,REJECT
-DOMAIN,data.flurry.com,REJECT
-DOMAIN,static.jpush.cn,REJECT
-DOMAIN,js.users.51.la,REJECT
-
-// Advertisement-Protection
-DOMAIN-SUFFIX,googleadservices.com,REJECT
-DOMAIN-SUFFIX,googlesyndication.com,REJECT
-DOMAIN-SUFFIX,googleadsserving.cn,REJECT
-DOMAIN-SUFFIX,admaster.com.cn,REJECT
-DOMAIN-SUFFIX,adinall.com,REJECT
-DOMAIN-SUFFIX,aerserv.com,REJECT
-DOMAIN-SUFFIX,adview.cn,REJECT
-DOMAIN-SUFFIX,cocounion.com,REJECT
-DOMAIN-SUFFIX,ctrmi.com,REJECT
-DOMAIN-SUFFIX,doubleclick.net,REJECT
-DOMAIN-SUFFIX,irs01.com,REJECT
-DOMAIN-SUFFIX,kejet.net,REJECT
-DOMAIN-SUFFIX,miaozhen.com,REJECT
-DOMAIN-SUFFIX,moatads.com,REJECT
-DOMAIN-SUFFIX,mopub.com,REJECT
-DOMAIN-SUFFIX,qchannel01.cn,REJECT
-DOMAIN-SUFFIX,tanx.com,REJECT
-DOMAIN-SUFFIX,tuanxue360.net,REJECT
-DOMAIN,ad.12306.cn,REJECT
-DOMAIN,adxserver.ad.cmvideo.cn,REJECT
-DOMAIN,ads-twitter.com,REJECT
-DOMAIN,adshow.58.com,REJECT
-DOMAIN,ads.simplepath.com,REJECT
-DOMAIN,ads.nexage.com,REJECT
-DOMAIN,adplatform.vrtcal.com,REJECT
-DOMAIN,ad.jiemian.com,REJECT
-DOMAIN,ggs.myzaker.com,REJECT
-DOMAIN,adshows.21cn.com,REJECT
-DOMAIN,ad-cn.jovcloud.com,REJECT
-DOMAIN,sugar.zhihu.com,REJECT
-
-// Baidu
-DOMAIN-SUFFIX,baidustatic.com,REJECT
-DOMAIN,hm.baidu.com,REJECT
-DOMAIN,hmma.baidu.com,REJECT
-DOMAIN,mobads.baidu.com,REJECT
-DOMAIN,mobads-logs.baidu.com,REJECT
-DOMAIN,wn.pos.baidu.com,REJECT
-// -Baidu_high-acc-ip
-DOMAIN,ps.map.baidu.com,REJECT
-DOMAIN,sv.map.baidu.com,REJECT
-DOMAIN,offnavi.map.baidu.com,REJECT
-DOMAIN,newvector.map.baidu.com,REJECT
-DOMAIN,ulog.imap.baidu.com,REJECT
-DOMAIN,newloc.map.n.shifen.com,REJECT
-
-// Ali
-DOMAIN,adash-c.ut.taobao.com,REJECT
-DOMAIN,adashxgc.ut.taobao.com,REJECT
-DOMAIN,adashbc.ut.taobao.com,REJECT
-DOMAIN,adash.man.aliyuncs.com,REJECT
-DOMAIN,apoll.m.taobao.com,REJECT
-DOMAIN,amdc.m.taobao.com,REJECT
-
-// Tencent
-DOMAIN,pingma.qq.com,REJECT
-DOMAIN,mi.gdt.qq.com,REJECT
-// -TencentVideo
-DOMAIN-SUFFIX,l.qq.com,REJECT
-DOMAIN,mtrace.qq.com,REJECT
-
-// 163
-DOMAIN-SUFFIX,analytics.126.net,REJECT
-DOMAIN,iadmat.nosdn.127.net,REJECT
-DOMAIN,static.ws.126.net,REJECT
-
-// AutoNavi
-DOMAIN,nbsdk-baichuan.alicdn.com,REJECT
-
-// iQiyi
-DOMAIN-SUFFIX,cupid.iqiyi.com,REJECT
-DOMAIN,ifacelog.iqiyi.com,REJECT
-DOMAIN,mbdlog.iqiyi.com,REJECT
-DOMAIN,msg.71.am,REJECT
-IP-CIDR,101.227.97.240/32,REJECT,no-resolve
-IP-CIDR,101.227.200.28/32,REJECT,no-resolve
-IP-CIDR,124.192.153.42/32,REJECT,no-resolve
-
-// Youku
-DOMAIN-SUFFIX,atm.youku.com,REJECT
-DOMAIN,ad.mobile.youku.com,REJECT
-DOMAIN,iyes.youku.com,REJECT
-
-// Sohu
-DOMAIN-SUFFIX,ads.sohu.com,REJECT
-// -SohuVideo
-DOMAIN-SUFFIX,aty.sohu.com,REJECT
-DOMAIN,imp.optaim.com,REJECT
-DOMAIN,v2.reachmax.cn,REJECT
-DOMAIN,data.vod.itc.cn,REJECT
-
-// Hunan_TV
-DOMAIN-SUFFIX,da.mgtv.com,REJECT
-DOMAIN-SUFFIX,da.hunantv.com,REJECT
-DOMAIN-SUFFIX,log.hunantv.com,REJECT
-DOMAIN,log.v2.hunantv.com,REJECT
-DOMAIN,v2.log.hunantv.com,REJECT
-
-// PPTV
-DOMAIN,asimgs.pplive.cn,REJECT
-
-// Le
-DOMAIN-SUFFIX,webp2p.letv.com,REJECT
-DOMAIN,ark.letv.com,REJECT
-DOMAIN,g3.letv.com,REJECT
-DOMAIN,n.mark.letv.com,REJECT
-
-// XiMaLaYa
-DOMAIN,ad.ximalaya.com,REJECT
-DOMAIN,adse.ximalaya.com,REJECT
-
-// Moji
-DOMAIN,ad.api.moji.com,REJECT
-DOMAIN,v1.log.moji.com,REJECT
-
-// Kugou and Kuwo
-DOMAIN,adserviceretry.kugou.com,REJECT
-DOMAIN,ads.service.kugou.com,REJECT
-DOMAIN,adsfile.bssdlbig.kugou.com,REJECT
-DOMAIN,log.stat.kugou.com,REJECT
-DOMAIN,log.web.kugou.com,REJECT
-DOMAIN,kgmobilestat.kugou.com,REJECT
-DOMAIN,kgmobilestatbak.kugou.com,REJECT
-DOMAIN,mobilelog.kugou.com,REJECT
-DOMAIN,mobilead.kuwo.cn,REJECT
-DOMAIN,rich.kuwo.cn,REJECT
-
-// Internet Service Provider Hijack
-DOMAIN-SUFFIX,cszlks.com,REJECT
-DOMAIN-SUFFIX,freedrive.cn,REJECT
-DOMAIN-SUFFIX,fkku194.com,REJECT
-DOMAIN-SUFFIX,fjlqqc.com,REJECT
-DOMAIN-SUFFIX,kumihua.com,REJECT
-DOMAIN-SUFFIX,mlnbike.com,REJECT
-DOMAIN-SUFFIX,quanliyouxi.cn,REJECT
-DOMAIN-SUFFIX,feih.com.cn,REJECT
-DOMAIN-SUFFIX,51chumoping.com,REJECT
-IP-CIDR,47.89.59.182/32,REJECT,no-resolve
-// -ChinaNet
-IP-CIDR,61.160.200.223/32,REJECT,no-resolve
-IP-CIDR,61.160.200.242/32,REJECT,no-resolve
-IP-CIDR,61.160.200.252/32,REJECT,no-resolve
-IP-CIDR,111.175.220.164/32,REJECT,no-resolve
-IP-CIDR,124.232.160.178/32,REJECT,no-resolve
-IP-CIDR,175.6.223.15/32,REJECT,no-resolve
-IP-CIDR,183.59.53.237/32,REJECT,no-resolve
-IP-CIDR,218.93.127.37/32,REJECT,no-resolve
-IP-CIDR,221.231.6.79/32,REJECT,no-resolve
-IP-CIDR,222.186.61.91/32,REJECT,no-resolve
-IP-CIDR,222.186.61.95/32,REJECT,no-resolve
-IP-CIDR,222.186.61.96/32,REJECT,no-resolve
-// -ChinaUnicom
-// -Dr.Peng
-IP-CIDR,10.72.25.13/32,REJECT,no-resolve
-IP-CIDR,115.182.16.79/32,REJECT,no-resolve
-IP-CIDR,118.144.88.126/32,REJECT,no-resolve
-IP-CIDR,118.144.88.215/32,REJECT,no-resolve
-IP-CIDR,124.14.21.147/32,REJECT,no-resolve
-IP-CIDR,124.14.21.151/32,REJECT,no-resolve
-IP-CIDR,180.166.52.24/32,REJECT,no-resolve
-IP-CIDR,220.115.251.25/32,REJECT,no-resolve
-IP-CIDR,222.73.156.235/32,REJECT,no-resolve
-
-// Blacklist
-DOMAIN-SUFFIX,makeding.com,REJECT
-DOMAIN-SUFFIX,mairuan.com,REJECT
-
-# REJECT End
-
-# Proxy Start
-
-// Apple
-DOMAIN-SUFFIX,appsto.re,Proxy
-DOMAIN-SUFFIX,me.com,Proxy
-DOMAIN,s.mzstatic.com,Proxy
-DOMAIN,gspe1-ssl.ls.apple.com,Proxy,force-remote-dns
-DOMAIN,news-events.apple.com,Proxy,force-remote-dns
-DOMAIN,news-client.apple.com,Proxy,force-remote-dns
-DOMAIN,lookup-api.apple.com,Proxy
-DOMAIN,api-glb-sea.smoot.apple.com,Proxy
-DOMAIN,books.itunes.apple.com,Proxy
-DOMAIN,hls.itunes.apple.com,Proxy
+tun-excluded-routes = 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 255.255.255.255/32
+skip-proxy = localhost, *.local, captive.apple.com, 0.0.0.0/8, 10.0.0.0/8, 17.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32
 
-// Google
-DOMAIN-SUFFIX,1e100.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,abc.xyz,Proxy,force-remote-dns
-DOMAIN-SUFFIX,admob.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,agoogleaday.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,ampproject.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,ampproject.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,ampproject.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,android.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,androidify.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,appspot.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,blogger.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,blogblog.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,certificate-transparency.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chrome.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chromecast.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chromeexperiments.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chromercise.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chromestatus.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,chromium.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,com.google,Proxy,force-remote-dns
-DOMAIN-SUFFIX,data-vocabulary.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,deja.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,digisfera.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,domains.google,Proxy,force-remote-dns
-DOMAIN-SUFFIX,feedburner.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,g.co,Proxy,force-remote-dns
-DOMAIN-SUFFIX,get.how,Proxy,force-remote-dns
-DOMAIN-SUFFIX,getmdl.io,Proxy,force-remote-dns
-DOMAIN-SUFFIX,ggpht.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gmail.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gmodules.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,goo.gl,Proxy,force-remote-dns
-DOMAIN-SUFFIX,google.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleapis.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleartproject.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleblog.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlecode.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlecommerce.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googledomains.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleearth.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googledrive.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlegroups.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlehosted.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleideas.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlelabs.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlemail.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleplay.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleplus.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlesource.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlesyndication.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googletagmanager.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googletagservices.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googleusercontent.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlevideo.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,googlezip.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gstatic.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gstatic.cn,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gvt0.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,gvt1.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,blogspot.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,html5rocks.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,iam.soy,Proxy,force-remote-dns
-DOMAIN-SUFFIX,igoogle.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,like.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,nic.google,Proxy,force-remote-dns
-DOMAIN-SUFFIX,panoramio.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,picasaweb.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,polymer-project.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,thinkwithgoogle.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,tiltbrush.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,recaptcha.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,registry.google,Proxy,force-remote-dns
-DOMAIN-SUFFIX,tensorflow.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,webmproject.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,whatbrowser.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,withgoogle.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,youtu.be,Proxy,force-remote-dns
-DOMAIN-SUFFIX,youtube.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,youtube-nocookie.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,ytimg.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,zynamics.com,Proxy,force-remote-dns
+allow-wifi-access = true
+wifi-access-http-port = 6152
+wifi-access-socks5-port = 6153
+http-listen = 0.0.0.0:6152
+socks5-listen = 0.0.0.0:6153
 
-// A
-DOMAIN-SUFFIX,amazon.com,Proxy
-DOMAIN-SUFFIX,amazonaws.com,Proxy
-DOMAIN-SUFFIX,archive.org,Proxy
-DOMAIN-SUFFIX,archive.is,Proxy
-DOMAIN-SUFFIX,archive.li,Proxy
-DOMAIN-SUFFIX,archives.gov,Proxy
-DOMAIN-SUFFIX,appdownloader.net,Proxy
-DOMAIN-SUFFIX,apk-dl.com,Proxy
-DOMAIN-SUFFIX,apkfind.com,Proxy
-DOMAIN-SUFFIX,apkpure.com,Proxy
-DOMAIN-SUFFIX,apigee.com,Proxy
-DOMAIN-SUFFIX,aol.com,Proxy
-DOMAIN-SUFFIX,aolcdn.com,Proxy
-DOMAIN-SUFFIX,anthonycalzadilla.com,Proxy
-DOMAIN-SUFFIX,android-x86.org,Proxy
-DOMAIN-SUFFIX,ancsconf.org,Proxy
-DOMAIN-SUFFIX,allconnected.co,Proxy
-DOMAIN-SUFFIX,apkleecher.com,Proxy
-DOMAIN-SUFFIX,appsonplaystore.com,Proxy
-DOMAIN-SUFFIX,awsstatic.com,Proxy
-DOMAIN-SUFFIX,async.be,Proxy
-DOMAIN-SUFFIX,appshopper.com,Proxy
-DOMAIN-SUFFIX,armorgames.com,Proxy
-DOMAIN-SUFFIX,avanquest.com,Proxy
-DOMAIN-SUFFIX,adaymag.com,Proxy
-DOMAIN-SUFFIX,app-measurement.com,Proxy
-DOMAIN-SUFFIX,akamaiedge.net,Proxy
+test-timeout = 4
+network-framework = true
+proxy-test-url = http://www.gstatic.com/generate_204
 
-// B
-DOMAIN-SUFFIX,bbc.com,Proxy
-DOMAIN-SUFFIX,books.com.tw,Proxy
-DOMAIN-SUFFIX,bloomberg.com,Proxy
-DOMAIN-SUFFIX,bloglovin.com,Proxy
-DOMAIN-SUFFIX,bitshare.com,Proxy
-DOMAIN-SUFFIX,bitcointalk.org,Proxy
-DOMAIN-SUFFIX,bit.do,Proxy
-DOMAIN-SUFFIX,bit.ly,Proxy
-DOMAIN-SUFFIX,bigsound.org,Proxy
-DOMAIN-SUFFIX,bbtoystore.com,Proxy
-DOMAIN-SUFFIX,boxun.com,Proxy
-DOMAIN-SUFFIX,bandwagonhost.com,Proxy
-DOMAIN-SUFFIX,bitvise.com,Proxy
-DOMAIN-SUFFIX,blessing.studio,Proxy
-DOMAIN-SUFFIX,btso.pw,Proxy
-DOMAIN-SUFFIX,binance.com,Proxy
-DOMAIN-SUFFIX,binance.cloud,Proxy
-DOMAIN-SUFFIX,bitstamp.net,Proxy
-DOMAIN-SUFFIX,beechat.io,Proxy
-DOMAIN-SUFFIX,bing.com,Proxy
-DOMAIN-SUFFIX,businessweek.com,Proxy
-DOMAIN-SUFFIX,bitfinex.com,Proxy
-DOMAIN-SUFFIX,bibox.com,Proxy
-DOMAIN-SUFFIX,bitmex.com,Proxy
-DOMAIN-SUFFIX,box.com,Proxy
-
-// C
-DOMAIN-SUFFIX,cnn.com,Proxy
-DOMAIN-SUFFIX,cdninstagram.com,Proxy
-DOMAIN-SUFFIX,cbc.ca,Proxy
-DOMAIN-SUFFIX,census.gov,Proxy
-DOMAIN-SUFFIX,cloudfront.net,Proxy
-DOMAIN-SUFFIX,cn-proxy.com,Proxy
-DOMAIN-SUFFIX,cccat.cc,Proxy
-DOMAIN-SUFFIX,codepen.io,Proxy
-DOMAIN-SUFFIX,cbsistatic.com,Proxy
-DOMAIN-SUFFIX,coinegg.com,Proxy
-DOMAIN-SUFFIX,css.network,Proxy
-DOMAIN-SUFFIX,cradio.live,Proxy
-
-// D
-DOMAIN-SUFFIX,dw.com,Proxy
-DOMAIN-SUFFIX,duckduckgo.com,Proxy
-DOMAIN-SUFFIX,dropbox.com,Proxy
-DOMAIN-SUFFIX,dropboxstatic.com,Proxy
-DOMAIN-SUFFIX,dropboxusercontent.com,Proxy
-DOMAIN-SUFFIX,disconnect.me,Proxy
-DOMAIN-SUFFIX,dcmilitary.com,Proxy
-DOMAIN-SUFFIX,digitaltrends.com,Proxy
-DOMAIN-SUFFIX,daolan.net,Proxy
-DOMAIN-SUFFIX,dol.gov,Proxy
-DOMAIN-SUFFIX,disqus.com,Proxy
-DOMAIN-SUFFIX,discuss.com.hk,Proxy
-DOMAIN-SUFFIX,discord.gg,Proxy
-DOMAIN-SUFFIX,discordapp.com,Proxy
-DOMAIN-SUFFIX,discordapp.net,Proxy
-DOMAIN-SUFFIX,doub.io,Proxy
-DOMAIN-SUFFIX,dnvod.tv,Proxy
-DOMAIN-SUFFIX,dailymotion.com,Proxy
-DOMAIN-SUFFIX,dwnews.com,Proxy
-DOMAIN-SUFFIX,dwnews.net,Proxy
-DOMAIN-SUFFIX,devmate.com,Proxy
-
-// E
-DOMAIN-SUFFIX,extmatrix.com,Proxy
-DOMAIN-SUFFIX,easybib.com,Proxy
-DOMAIN-SUFFIX,easybib.com,Proxy
-DOMAIN-SUFFIX,economist.com,Proxy
-DOMAIN-SUFFIX,edgecastcdn.net,Proxy
-DOMAIN-SUFFIX,everhelper.me,Proxy
-DOMAIN-SUFFIX,envato-static.com,Proxy
-
-// F
-DOMAIN-SUFFIX,facebook.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,facebook.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,fbcdn.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,fb.com,Proxy
-DOMAIN-SUFFIX,fb.me,Proxy
-DOMAIN-SUFFIX,freeopenProxy.com,Proxy
-DOMAIN-SUFFIX,fzlm.net,Proxy
-DOMAIN-SUFFIX,flitto.com,Proxy
-DOMAIN-SUFFIX,flipkart.com,Proxy
-DOMAIN-SUFFIX,flickr.com,Proxy
-DOMAIN-SUFFIX,staticflickr.com,Proxy
-DOMAIN-SUFFIX,fdlstatic.com,Proxy
-DOMAIN-SUFFIX,fastly.net,Proxy
-DOMAIN-SUFFIX,flumeapp.com,Proxy
-DOMAIN-SUFFIX,free-proxy.cz,Proxy
-DOMAIN-SUFFIX,fc2.com,Proxy
-DOMAIN-SUFFIX,firebaseio.com,Proxy
-DOMAIN-SUFFIX,flightradar24.com,Proxy
-
-// G
-DOMAIN-SUFFIX,getcloudapp.com,Proxy
-DOMAIN-SUFFIX,gunsamerica.com,Proxy
-DOMAIN-SUFFIX,gravatar.com,Proxy
-DOMAIN-SUFFIX,getlantern.org,Proxy
-DOMAIN-SUFFIX,getfoxyProxy.org,Proxy
-DOMAIN-SUFFIX,go.com,Proxy
-DOMAIN-SUFFIX,go.jp,Proxy
-DOMAIN-SUFFIX,gfw.press,Proxy
-DOMAIN-SUFFIX,getdropbox.com,Proxy
-DOMAIN-SUFFIX,github.io,Proxy
-DOMAIN-SUFFIX,gitbooks.io,Proxy
-DOMAIN-SUFFIX,greatfire.org,Proxy
-DOMAIN-SUFFIX,getsync.com,Proxy
-DOMAIN-SUFFIX,gumroad.com,Proxy
-DOMAIN-SUFFIX,gdax.com,Proxy
-DOMAIN-SUFFIX,gate.io,Proxy
-DOMAIN-SUFFIX,gracecode.com,Proxy
-DOMAIN,gist.github.com,Proxy
-
-// H
-DOMAIN-SUFFIX,howtoforge.com,Proxy
-DOMAIN-SUFFIX,hootsuite.com,Proxy
-DOMAIN-SUFFIX,homedepot.com,Proxy
-DOMAIN-SUFFIX,hulu.com,Proxy
-DOMAIN-SUFFIX,hk01.com,Proxy
-DOMAIN-SUFFIX,huobi.com,Proxy
-DOMAIN-SUFFIX,huobi.pro,Proxy
-DOMAIN-SUFFIX,huobipro.com,Proxy
-DOMAIN-SUFFIX,hitbtc.com,Proxy
-
-// I
-DOMAIN-SUFFIX,instagram.com,Proxy
-DOMAIN-SUFFIX,icoco.com,Proxy
-DOMAIN-SUFFIX,imgur.com,Proxy
-DOMAIN-SUFFIX,instructables.com,Proxy
-DOMAIN-SUFFIX,ift.tt,Proxy
-DOMAIN-SUFFIX,is.gd,Proxy
-DOMAIN-SUFFIX,imgbus.com,Proxy
-DOMAIN-SUFFIX,i-scmp.com,Proxy
-DOMAIN-SUFFIX,iask.ca,Proxy
-DOMAIN-SUFFIX,issuu.com,Proxy
-DOMAIN-SUFFIX,ixquick.com,Proxy
-DOMAIN-SUFFIX,init.shop,Proxy
-DOMAIN-SUFFIX,initiummall.com,Proxy
-DOMAIN-SUFFIX,ipfs.io,Proxy
-
-// J
-DOMAIN-SUFFIX,jwpcdn.com,Proxy
-DOMAIN-SUFFIX,jwpltx.com,Proxy
-
-// K
-DOMAIN-SUFFIX,kenengba.com,Proxy
-DOMAIN-SUFFIX,keepvid.com,Proxy
-DOMAIN-SUFFIX,kobo.com,Proxy
-DOMAIN-SUFFIX,kucoin.com,Proxy
-
-// L
-DOMAIN-SUFFIX,line.me,Proxy
-DOMAIN-SUFFIX,line-apps.com,Proxy
-DOMAIN-SUFFIX,line-cdn.net,Proxy
-DOMAIN-SUFFIX,line-scdn.net,Proxy
-DOMAIN-SUFFIX,logmein.com,Proxy
-DOMAIN-SUFFIX,lvv2.com,Proxy
-DOMAIN-SUFFIX,live.com,Proxy
-DOMAIN-SUFFIX,linkcoin.pro,Proxy
-
-// M
-DOMAIN-SUFFIX,mp3buscador.com,Proxy
-DOMAIN-SUFFIX,medium.com,Proxy
-DOMAIN-SUFFIX,mlssoccer.com,Proxy
-DOMAIN-SUFFIX,marketwatch.com,Proxy
-DOMAIN-SUFFIX,nih.gov,Proxy
-DOMAIN-SUFFIX,mycnnews.com,Proxy
-DOMAIN-SUFFIX,maplestage.com,Proxy
-DOMAIN-SUFFIX,mozilla.net,Proxy
-DOMAIN-SUFFIX,mobypicture.com,Proxy
-DOMAIN-SUFFIX,msn.com,Proxy
-
-// N
-DOMAIN-SUFFIX,nytimes.com,Proxy
-DOMAIN-SUFFIX,nytimg.com,Proxy
-DOMAIN-SUFFIX,nyti.ms,Proxy
-DOMAIN-SUFFIX,nytstyle.com,Proxy
-DOMAIN-SUFFIX,nyt.com,Proxy
-DOMAIN-SUFFIX,nrk.no,Proxy
-DOMAIN-SUFFIX,newipnow.com,Proxy
-DOMAIN-SUFFIX,ndr.de,Proxy
-DOMAIN-SUFFIX,nasa.gov,Proxy
-DOMAIN-SUFFIX,netflix.com,Proxy
-DOMAIN-SUFFIX,netflix.net,Proxy
-DOMAIN-SUFFIX,nflxext.com,Proxy
-DOMAIN-SUFFIX,nflximg.com,Proxy
-DOMAIN-SUFFIX,nflximg.net,Proxy
-DOMAIN-SUFFIX,nflxvideo.net,Proxy
-DOMAIN-SUFFIX,nflxso.net,Proxy
-DOMAIN-SUFFIX,nintendo.com,Proxy
-DOMAIN-SUFFIX,nssurge.com,Proxy
-DOMAIN-SUFFIX,neverware.com,Proxy
-DOMAIN-SUFFIX,ngrok.cc,Proxy
-DOMAIN-SUFFIX,naver.jp,Proxy
-
-// O
-DOMAIN-SUFFIX,onlineyoutube.com,Proxy
-DOMAIN-SUFFIX,osha.gov,Proxy
-DOMAIN-SUFFIX,optimizely.com,Proxy
-DOMAIN-SUFFIX,owncloud.org,Proxy
-DOMAIN-SUFFIX,ow.ly,Proxy
-DOMAIN-SUFFIX,oup.com,Proxy
-DOMAIN-SUFFIX,ok.ru,Proxy
-DOMAIN-SUFFIX,oloadcdn.net,Proxy
-DOMAIN-SUFFIX,okex.com,Proxy
-
-// P
-DOMAIN-SUFFIX,psiphon3.com,Proxy
-DOMAIN-SUFFIX,puffinbrowser.com,Proxy
-DOMAIN-SUFFIX,pubu.com.tw,Proxy
-DOMAIN-SUFFIX,proxfree.com,Proxy
-DOMAIN-SUFFIX,popo.tw,Proxy
-DOMAIN-SUFFIX,pokemon.com,Proxy
-DOMAIN-SUFFIX,pastebin.com,Proxy
-DOMAIN-SUFFIX,pandora.com,Proxy
-DOMAIN-SUFFIX,pinterest.com,Proxy
-DOMAIN-SUFFIX,pinimg.com,Proxy
-DOMAIN-SUFFIX,pandora.com,Proxy
-DOMAIN-SUFFIX,potatso.com,Proxy
-DOMAIN-SUFFIX,pscp.tv,Proxy
-DOMAIN-SUFFIX,putty.org,Proxy
-DOMAIN-SUFFIX,pixiv.net,Proxy
-DOMAIN-SUFFIX,pixiv.org,Proxy
-DOMAIN-SUFFIX,pixnet.net,Proxy
-DOMAIN-SUFFIX,pentoy.hk,Proxy
-DOMAIN-SUFFIX,psu.edu,Proxy
-DOMAIN-SUFFIX,poloniex.com,Proxy
-
-// R
-DOMAIN-SUFFIX,rsf.org,Proxy
-DOMAIN-SUFFIX,rileyguide.com,Proxy
-DOMAIN-SUFFIX,rfi.fr,Proxy
-DOMAIN-SUFFIX,reuters.com,Proxy
-DOMAIN-SUFFIX,readmoo.com,Proxy
-DOMAIN-SUFFIX,readingtimes.com.tw,Proxy
-DOMAIN-SUFFIX,resilio.com,Proxy
-DOMAIN-SUFFIX,rawgit.com,Proxy
-DOMAIN-SUFFIX,rackcdn.com,Proxy
-DOMAIN-SUFFIX,rthk.hk,Proxy
-
-// S
-DOMAIN-SUFFIX,scribd.com,Proxy
-DOMAIN-SUFFIX,sydneytoday.com,Proxy
-DOMAIN-SUFFIX,surrenderat20.net,Proxy
-DOMAIN-SUFFIX,surfeasy.com.au,Proxy
-DOMAIN-SUFFIX,sugarsync.com,Proxy
-DOMAIN-SUFFIX,stumbleupon.com,Proxy
-DOMAIN-SUFFIX,storify.com,Proxy
-DOMAIN-SUFFIX,startpage.com,Proxy
-DOMAIN-SUFFIX,starp2p.com,Proxy
-DOMAIN-SUFFIX,state.gov,Proxy
-DOMAIN-SUFFIX,spike.com,Proxy
-DOMAIN-SUFFIX,sowers.org.hk,Proxy
-DOMAIN-SUFFIX,soundcloud.com,Proxy
-DOMAIN-SUFFIX,sockslist.net,Proxy
-DOMAIN-SUFFIX,snapchat.com,Proxy
-DOMAIN-SUFFIX,smh.com.au,Proxy
-DOMAIN-SUFFIX,slideshare.net,Proxy
-DOMAIN-SUFFIX,skype.com,Proxy
-DOMAIN-SUFFIX,sketchappsources.com,Proxy
-DOMAIN-SUFFIX,sidelinesnews.com,Proxy
-DOMAIN-SUFFIX,shadowsocks.org,Proxy
-DOMAIN-SUFFIX,search.com,Proxy
-DOMAIN-SUFFIX,sciencemag.org,Proxy
-DOMAIN-SUFFIX,ssa.gov,Proxy
-DOMAIN-SUFFIX,shutterstock.com,Proxy
-DOMAIN-SUFFIX,sciencedaily.com,Proxy
-DOMAIN-SUFFIX,signalsitemap.com,Proxy
-DOMAIN-SUFFIX,surge.run,Proxy
-DOMAIN-SUFFIX,swtch.com,Proxy
-DOMAIN-SUFFIX,scmp.com,Proxy
-DOMAIN-SUFFIX,stel.com,Proxy
-DOMAIN-SUFFIX,steamcommunity.com,Proxy
-DOMAIN-SUFFIX,slack.com,Proxy
-DOMAIN-SUFFIX,slack-edge.com,Proxy
-DOMAIN-SUFFIX,slack-msgs.com,Proxy
-DOMAIN-SUFFIX,sndcdn.com,Proxy
-
-// T
-DOMAIN-SUFFIX,twtkr.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twimg.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twitthat.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twitterrific.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twittercounter.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twittergadget.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twitterfeed.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twitter4j.org,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twttr.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,twitter.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,t.co,Proxy,force-remote-dns
-DOMAIN-SUFFIX,tv.com,Proxy
-DOMAIN-SUFFIX,tumblr.com,Proxy
-DOMAIN-SUFFIX,tmblr.co,Proxy
-DOMAIN-SUFFIX,txmblr.com,Proxy
-DOMAIN-SUFFIX,turbobit.net,Proxy
-DOMAIN-SUFFIX,tt-rss.org,Proxy
-DOMAIN-SUFFIX,trulyergonomic.com,Proxy
-DOMAIN-SUFFIX,trendsmap.com,Proxy
-DOMAIN-SUFFIX,transparency.org,Proxy
-DOMAIN-SUFFIX,traffichaus.com,Proxy
-DOMAIN-SUFFIX,torrentz.eu,Proxy
-DOMAIN-SUFFIX,torrentproject.se,Proxy
-DOMAIN-SUFFIX,torrentprivacy.com,Proxy
-DOMAIN-SUFFIX,torproject.org,Proxy
-DOMAIN-SUFFIX,torcn.com,Proxy
-DOMAIN-SUFFIX,tokyocn.com,Proxy
-DOMAIN-SUFFIX,togetter.com,Proxy
-DOMAIN-SUFFIX,tinychat.com,Proxy
-DOMAIN-SUFFIX,tiny.cc,Proxy
-DOMAIN-SUFFIX,time.com,Proxy
-DOMAIN-SUFFIX,thewgo.org,Proxy
-DOMAIN-SUFFIX,thepiratebay.org,Proxy
-DOMAIN-SUFFIX,thebobs.com,Proxy
-DOMAIN-SUFFIX,telegram.org,Proxy
-DOMAIN-SUFFIX,telegram.me,Proxy
-DOMAIN-SUFFIX,telegram.show,Proxy
-DOMAIN-SUFFIX,technorati.com,Proxy
-DOMAIN-SUFFIX,talkboxapp.com,Proxy
-DOMAIN-SUFFIX,talkonly.net,Proxy
-DOMAIN-SUFFIX,talk853.com,Proxy
-DOMAIN-SUFFIX,tabtter.jp,Proxy
-DOMAIN-SUFFIX,tablesgenerator.com,Proxy
-DOMAIN-SUFFIX,tomshardware.com,Proxy
-DOMAIN-SUFFIX,theverge.com,Proxy
-DOMAIN-SUFFIX,twishort.com,Proxy
-DOMAIN-SUFFIX,tdesktop.com,Proxy
-DOMAIN-SUFFIX,t.me,Proxy
-DOMAIN-SUFFIX,tv-static.net,Proxy
-DOMAIN-SUFFIX,theinitium.com,Proxy
-DOMAIN-SUFFIX,trellocdn.com,Proxy
-DOMAIN-SUFFIX,tvcdn.de,Proxy
-DOMAIN-SUFFIX,textnow.me,Proxy
-
-// U
-DOMAIN-SUFFIX,ustream.tv,Proxy
-DOMAIN-SUFFIX,uspto.gov,Proxy
-DOMAIN-SUFFIX,usma.edu,Proxy
-DOMAIN-SUFFIX,us.to,Proxy
-DOMAIN-SUFFIX,urlparser.com,Proxy
-DOMAIN-SUFFIX,uProxy.org,Proxy
-DOMAIN-SUFFIX,uploaded.net,Proxy
-DOMAIN-SUFFIX,untraceable.us,Proxy
-DOMAIN-SUFFIX,unpo.org,Proxy
-DOMAIN-SUFFIX,unblocksites.co,Proxy
-DOMAIN-SUFFIX,unblockdmm.com,Proxy
-DOMAIN-SUFFIX,uhdwallpapers.org,Proxy
-DOMAIN-SUFFIX,ugo.com,Proxy
-DOMAIN-SUFFIX,udn.com,Proxy
-DOMAIN-SUFFIX,uchicago.edu,Proxy
-DOMAIN-SUFFIX,usgs.gov,Proxy
-DOMAIN-SUFFIX,umblr.com,Proxy
-DOMAIN-SUFFIX,unpkg.com,Proxy
-
-// V
-DOMAIN-SUFFIX,vpngate.net,Proxy
-DOMAIN-SUFFIX,vocativ.com,Proxy
-DOMAIN-SUFFIX,visibletweets.com,Proxy
-DOMAIN-SUFFIX,vimperator.org,Proxy
-DOMAIN-SUFFIX,vimeo.com,Proxy
-DOMAIN-SUFFIX,vimeocdn.com,Proxy
-DOMAIN-SUFFIX,vidinfo.org,Proxy
-DOMAIN-SUFFIX,videomega.tv,Proxy
-DOMAIN-SUFFIX,vid.me,Proxy
-DOMAIN-SUFFIX,viber.com,Proxy
-DOMAIN-SUFFIX,veoh.com,Proxy
-DOMAIN-SUFFIX,venchina.com,Proxy
-DOMAIN-SUFFIX,vansky.com,Proxy
-DOMAIN-SUFFIX,vanpeople.com,Proxy
-DOMAIN-SUFFIX,van001.com,Proxy
-DOMAIN-SUFFIX,v2ray.com,Proxy
-DOMAIN-SUFFIX,verizonwireless.com,Proxy
-DOMAIN-SUFFIX,vzw.com,Proxy
-DOMAIN-SUFFIX,voachinese.com,Proxy
-DOMAIN-SUFFIX,vnet.link,Proxy
-DOMAIN-SUFFIX,voanews.com,Proxy
-DOMAIN-SUFFIX,vanilla-js.com,Proxy
-DOMAIN-SUFFIX,vjmedia.com.hk,Proxy
-
-// W
-DOMAIN-SUFFIX,wwitv.com,Proxy
-DOMAIN-SUFFIX,wsj.com,Proxy
-DOMAIN-SUFFIX,wsj.net,Proxy
-DOMAIN-SUFFIX,wordpress.com,Proxy
-DOMAIN-SUFFIX,wp.com,Proxy
-DOMAIN-SUFFIX,wow.com,Proxy
-DOMAIN-SUFFIX,worldcat.org,Proxy
-DOMAIN-SUFFIX,wn.com,Proxy
-DOMAIN-SUFFIX,wikipedia.org,Proxy
-DOMAIN-SUFFIX,wikipedia.com,Proxy
-DOMAIN-SUFFIX,wikimedia.org,Proxy
-DOMAIN-SUFFIX,wikileaks.info,Proxy
-DOMAIN-SUFFIX,wikileaks-forum.com,Proxy
-DOMAIN-SUFFIX,wikileaks.org,Proxy
-DOMAIN-SUFFIX,westpoint.edu,Proxy
-DOMAIN-SUFFIX,westca.com,Proxy
-DOMAIN-SUFFIX,wenxuecity.com,Proxy
-DOMAIN-SUFFIX,webwarper.net,Proxy
-DOMAIN-SUFFIX,websnapr.com,Proxy
-DOMAIN-SUFFIX,weblagu.com,Proxy
-DOMAIN-SUFFIX,webfreer.com,Proxy
-DOMAIN-SUFFIX,web2project.net,Proxy
-DOMAIN-SUFFIX,wattpad.com,Proxy
-DOMAIN-SUFFIX,winudf.com,Proxy
-DOMAIN-SUFFIX,web.de,Proxy
-DOMAIN-SUFFIX,wanqu.co,Proxy
-DOMAIN-SUFFIX,whoer.net,Proxy
-DOMAIN-SUFFIX,whatsapp.net,Proxy,force-remote-dns
-DOMAIN-SUFFIX,whatsapp.com,Proxy,force-remote-dns
-DOMAIN-SUFFIX,webpagefx.com,Proxy
-
-// X
-DOMAIN-SUFFIX,xuite.net,Proxy
-DOMAIN-SUFFIX,xanga.com,Proxy
-
-// Y
-DOMAIN-SUFFIX,yahoo.com,Proxy
-DOMAIN-SUFFIX,yimg.com,Proxy
-DOMAIN-SUFFIX,yourlisten.com,Proxy
-DOMAIN-SUFFIX,youmaker.com,Proxy
-DOMAIN-SUFFIX,yorkbbs.ca,Proxy
-DOMAIN-SUFFIX,yidio.com,Proxy
-DOMAIN-SUFFIX,yes-news.com,Proxy
-DOMAIN-SUFFIX,yesasia.com,Proxy
-DOMAIN-SUFFIX,yeeyi.com,Proxy
-DOMAIN-SUFFIX,yasni.co.uk,Proxy
-DOMAIN-SUFFIX,yastatic.net,Proxy
-
-// Z
-DOMAIN-SUFFIX,zacebook.com,Proxy
-DOMAIN-SUFFIX,zalmos.com,Proxy
-DOMAIN-SUFFIX,zaobao.com.sg,Proxy
-DOMAIN-SUFFIX,zeutch.com,Proxy
-DOMAIN-SUFFIX,zeronet.io,Proxy
-DOMAIN-SUFFIX,zdassets.com,Proxy
-DOMAIN-SUFFIX,zhowkev.in,Proxy
-DOMAIN-SUFFIX,zb.com,Proxy
-
-
-// 0-9
-DOMAIN-SUFFIX,4everProxy.com,Proxy
-DOMAIN-SUFFIX,4shared.com,Proxy
-DOMAIN-SUFFIX,6park.com,Proxy
+external-controller-access = surgepasswd@0.0.0.0:6170
+exclude-simple-hostnames = true
+ipv6 = false
+replica = false
 
-// Telegram
-IP-CIDR,91.108.0.0/16,Proxy,no-resolve
-IP-CIDR,149.154.0.0/16,Proxy,no-resolve
+[Replica]
+hide-apple-request = true
+hide-crashlytics-request = true
+use-keyword-filter = false
+hide-udp = false
 
-// LINE
-IP-CIDR,103.2.28.0/20,Proxy,no-resolve
-IP-CIDR,119.235.224.0/20,Proxy,no-resolve
-IP-CIDR,125.209.222.0/16,Proxy,no-resolve
-IP-CIDR,147.92.128.0/21,Proxy,no-resolve
-IP-CIDR,203.104.128.0/19,Proxy,no-resolve
+# -----------------------------
+# Surge 的几种策略配置规范,请参考 https://manual.nssurge.com/policy/proxy.html
+# Surge 现已支持 UDP 转发功能,请参考: https://trello.com/c/ugOMxD3u/53-udp-%E8%BD%AC%E5%8F%91
+# Surge 现已支持 TCP-Fast-Open 技术,请参考: https://trello.com/c/ij65BU6Q/48-tcp-fast-open-troubleshooting-guide
+# Surge 现已支持 ss-libev 的全部加密方式和混淆,请参考: https://trello.com/c/BTr0vG1O/47-ss-libev-%E7%9A%84%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5
+# -----------------------------
 
-// Others Proxy
-IP-CIDR,18.0.0.0/8,Proxy,no-resolve
-IP-CIDR,31.0.0.0/8,Proxy,no-resolve
-IP-CIDR,35.0.0.0/8,Proxy,no-resolve
-IP-CIDR,52.0.0.0/8,Proxy,no-resolve
-IP-CIDR,54.0.0.0/8,Proxy,no-resolve
-IP-CIDR,64.0.0.0/8,Proxy,no-resolve
-IP-CIDR,75.0.0.0/8,Proxy,no-resolve
-IP-CIDR,158.0.0.0/8,Proxy,no-resolve
-IP-CIDR,169.0.0.0/8,Proxy,no-resolve
-IP-CIDR,174.0.0.0/8,Proxy,no-resolve
-IP-CIDR,199.0.0.0/8,Proxy,no-resolve
+[Proxy]
+$proxies
 
-# Proxy End
+[Proxy Group]
+Proxy = select, auto, fallback, $proxy_group
+auto = url-test, $proxy_group, url=http://www.gstatic.com/generate_204, interval=43200
+fallback = fallback, $proxy_group, url=http://www.gstatic.com/generate_204, interval=43200
 
-GEOIP, CN, DIRECT
-FINAL, Proxy
+[Rule]
+# 自定义规则
+## 您可以在此处插入自定义规则
+
+# 实用规则片段集
+# RULE-SET,SYSTEM,DIRECT
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/Basic/Apple-proxy.list,Proxy
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/Basic/Apple-direct.list,DIRECT
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/Basic/CN.list,DIRECT
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/Basic/common-ad-keyword.list,REJECT-TINYGIF
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/Basic/foreign.list,Proxy
+RULE-SET,https://cdn.jsdelivr.net/gh/Hackl0us/SS-Rule-Snippet@master/Rulesets/App/social/Telegram.list,Proxy
+RULE-SET,LAN,DIRECT
+
+# 最终规则
+GEOIP,CN,DIRECT
+FINAL,Proxy,dns-failed
 
 [URL Rewrite]
-// Redirect_Google_Service
-^https?://(www.)?g.cn https://www.google.com 302
-^https?://(www.)?google.cn https://www.google.com 302
+^https?://(www.)?(g|google).cn https://www.google.com 302

+ 1 - 1
resources/views/admin.blade.php

@@ -11,7 +11,7 @@
     <!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> -->
     <script>window.routerBase = "/";</script>
     <script>
-        window.v2board = {
+        window.settings = {
             title: '{{$title}}',
             theme: {
                 sidebar: '{{$theme_sidebar}}',

+ 1 - 1
resources/views/app.blade.php

@@ -11,7 +11,7 @@
     <!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> -->
     <script>window.routerBase = "/";</script>
     <script>
-        window.v2board = {
+        window.settings = {
             title: '{{$title}}',
             theme: {
                 sidebar: '{{$theme_sidebar}}',

Some files were not shown because too many files changed in this diff