云边日落 云边日落
  • 首页
  • 随笔
    • 生活随记
    • 思考感悟
    • 阅读笔记
  • 笔记
    • 编程开发
    • 环境配置
    • 问题解决
  • 资源
    • 软件推荐
    • 学习资料
    • 开源推荐
  • 友链
  • 关于

酒笙

管理员
IP归属地: 香港
文章
13
评论
1

推荐用户

酒笙

酒笙

青栀

青栀

酒笙
2 月前 香港

飞猫M20短信转发功能实现:飞书通知与自启

前言

飞猫M20是一款实用的随身WiFi设备,除了基本的网络功能外,我们还可以深度挖掘其潜力,实现短信自动转发功能。本文将详细介绍如何在这款设备上实现短信内容自动推送到飞书,并确保系统重启后服务能自动运行,让您随时随地掌握重要短信信息。

飞猫M20短信转发功能实现:飞书通知与自启-云边日落

实现原理

飞猫M20运行的是基于BusyBox的嵌入式Linux系统。通过编写Shell脚本实现短信监控和转发的核心功能,再配合系统自启动配置,确保服务的持久运行。整个过程主要包括:

  1. 自动登录设备管理界面
  2. 定期检查新短信
  3. 解析短信内容
  4. 通过飞书Webhook推送通知
  5. 配置系统自启动

核心脚本实现

1. 短信转发主脚本 (sms_forward.sh)

这是实现短信转发功能的核心脚本:

#!/bin/sh
​
# 检查是否已经有实例在运行
LOCKFILE="/tmp/sms_forward.lock"
if [ -e "$LOCKFILE" ] && kill -0 $(cat "$LOCKFILE") 2>/dev/null; then
   echo "短信转发服务已经在运行"
   exit 1
fi
​
# 设置锁定文件
echo $$ > "$LOCKFILE"
trap "rm -f '$LOCKFILE'" EXIT
​
# 配置 - 请根据需要修改这些值
SMS_API_URL="http://192.168.88.1/action/sms_get_sms_list"
LOGIN_URL="http://192.168.88.1/goform/login"
SYNC_URL="http://192.168.88.1/goform/sync"
FEISHU_WEBHOOK_URL="飞书webhook地址"
CHECK_INTERVAL=15  # 每隔几秒检查一次
DEVICE_MODEL="设备名称"
SIM_INFO="手机号"
​
# 文件路径
LAST_INDEX_FILE="/tmp/last_sms_index.txt"
LOG_FILE="/tmp/sms_forward.log"
COOKIE_FILE="/tmp/sms_session_cookie.txt"
​
# 如果索引文件不存在,则初始化
if [ ! -f "$LAST_INDEX_FILE" ]; then
   echo "0" > "$LAST_INDEX_FILE"
fi
​
# 日志函数
log() {
  local message="$1"
   echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message" >> "$LOG_FILE"
   echo "[$(date '+%Y-%m-%d %H:%M:%S')] $message"
}
​
# 启动日志
log "短信转发服务已启动"
​
# 获取会话Cookie的函数
get_session_cookie() {
   # 清理旧的cookie文件
   rm -f "$COOKIE_FILE" "$COOKIE_FILE.session" 2>/dev/null
​
   # 步骤1: 首先获取同步请求和初始Cookie
   SYNC_RESPONSE=$(curl -s -i -X POST "$SYNC_URL" \
      -H 'User-Agent: Mozilla/5.0' \
      -H 'Accept: text/plain, */*; q=0.01' \
      -H 'Pragma: no-cache' \
      -H 'Cache-Control: no-cache' \
      -H 'X-Requested-With: XMLHttpRequest' \
      -H 'Content-Type: application/x-mgdata' \
      -H 'Origin: http://192.168.88.1' \
      -H 'Referer: http://192.168.88.1/common/login.html')
​
   # 提取Cookie
   SESSION_COOKIE=$(echo "$SYNC_RESPONSE" | grep -i "Set-Cookie:" | sed 's/^Set-Cookie: //i' | sed 's/;.*$//')
   
   # 如果无法获取Cookie,则退出
   if [ -z "$SESSION_COOKIE" ]; then
      log "错误: 无法获取会话Cookie"
      return 1
   fi
   
   echo "$SESSION_COOKIE" > "$COOKIE_FILE"
​
   # 步骤2: 使用静态加密值进行登录,并获取登录后的新Cookie
   # 使用固定的加密值 - 这些值在网页中已经预先计算好
   USERNAME_STATIC="4cc68e3626e5b94602c325f7c4ca5dee"
   PASSWORD_STATIC="95bf0786a20922aec868627af48aa872"
   REMEMBER_STATIC="d2e6057958b411672c3028b1976a41e1"
​
   LOGIN_DATA="{\"username\":\"$USERNAME_STATIC\",\"password\":\"$PASSWORD_STATIC\",\"remember\":\"$REMEMBER_STATIC\"}"
​
   LOGIN_RESPONSE=$(curl -s -i -X POST "$LOGIN_URL" \
      -H 'User-Agent: Mozilla/5.0' \
      -H 'Accept: application/json, text/javascript, */*; q=0.01' \
      -H 'Content-Type: application/json' \
      -H 'Pragma: no-cache' \
      -H 'Cache-Control: no-cache' \
      -H 'X-Requested-With: XMLHttpRequest' \
      -H 'Origin: http://192.168.88.1' \
      -H 'Referer: http://192.168.88.1/common/login.html' \
      -H "Cookie: $SESSION_COOKIE" \
      -d "$LOGIN_DATA")
​
   # 从登录响应中提取新的Cookie
   AUTH_COOKIE=$(echo "$LOGIN_RESPONSE" | grep -i "Set-Cookie:" | sed 's/^Set-Cookie: //i' | sed 's/;.*$//')
   
   # 检查登录响应是否成功
   if echo "$LOGIN_RESPONSE" | grep -q '"retcode":0'; then
       if [ -n "$AUTH_COOKIE" ]; then
           echo "$AUTH_COOKIE" > "$COOKIE_FILE.session"
       else
           cp "$COOKIE_FILE" "$COOKIE_FILE.session"
       fi
      return 0
   else
      log "错误: 登录失败"
      return 1
   fi
}
​
# 提取指定索引的短信数据
extract_sms_data() {
  local JSON="$1"
  local INDEX="$2"
  local TEMP_FILE="/tmp/sms_all.txt"
   
   # 使用简单直接的方法:先提取所有短信到单独文件
   echo "$JSON" | sed 's/{"index":/\n{"index":/g' > "$TEMP_FILE"
   
   # 使用简单字符串匹配来查找目标短信
   grep "\"index\":$INDEX," "$TEMP_FILE" > "/tmp/sms_found.txt"
   
   if [ ! -s "/tmp/sms_found.txt" ]; then
      log "错误: 无法找到索引为 $INDEX 的短信"
       rm -f "$TEMP_FILE" "/tmp/sms_found.txt"
      return 1
   fi
   
   # 从匹配行中提取字段
   FOUND_LINE=$(cat "/tmp/sms_found.txt")
   PHONE=$(echo "$FOUND_LINE" | sed 's/.*"phone":"\([^"]*\)".*/\1/')
   DATETIME=$(echo "$FOUND_LINE" | sed 's/.*"datetime":\([0-9]*\).*/\1/')
   CONTENT=$(echo "$FOUND_LINE" | sed 's/.*"content":"\([^"]*\)".*/\1/')
   
   # 清理临时文件
   rm -f "$TEMP_FILE" "/tmp/sms_found.txt"
   
   # 验证提取结果
   if [ -z "$PHONE" ] || [ -z "$CONTENT" ]; then
      log "错误: 无法正确提取短信 #$INDEX 的数据"
      return 1
   fi
  return 0
}
​
# 主循环
while true; do
   # 获取上次处理的最新短信索引
   LAST_INDEX=$(cat "$LAST_INDEX_FILE")
​
   # 检查是否有有效的会话Cookie
   if [ ! -f "$COOKIE_FILE.session" ]; then
      log "获取新的会话凭证"
      get_session_cookie
       if [ $? -ne 0 ]; then
          log "无法获取有效的会话凭证,将在5分钟后重试"
           sleep 300
          continue
       fi
   fi
​
   # 获取短信列表
   SESSION_COOKIE=$(cat "$COOKIE_FILE.session")
   SMS_RESPONSE=$(curl -s "$SMS_API_URL" \
      -H 'User-Agent: Mozilla/5.0' \
      -H 'Accept: application/json, text/javascript, */*; q=0.01' \
      -H 'Content-Type: application/json' \
      -H 'Pragma: no-cache' \
      -H 'X-Requested-With: XMLHttpRequest' \
      -H 'Origin: http://192.168.88.1' \
      -H 'Referer: http://192.168.88.1/html/settings.html' \
      -H "Cookie: $SESSION_COOKIE" \
      --data-raw '{"start":1,"end":10,"smsbox":1}')
​
   # 检查响应是否有效
   if echo "$SMS_RESPONSE" | grep -q '"retcode":0'; then
       # 提取所有索引并排序
       echo "$SMS_RESPONSE" | grep -o '"index":[0-9]*' | sed 's/"index"://g' > /tmp/sms_indices.txt
       sort -nr /tmp/sms_indices.txt > /tmp/sms_indices_sorted.txt
       
       # 获取最高索引 (第一行)
       HIGHEST_INDEX=$(sed -n '1p' /tmp/sms_indices_sorted.txt)
       
       # 只有当有新消息时才处理
       if [ -n "$HIGHEST_INDEX" ] && [ "$HIGHEST_INDEX" -gt "$LAST_INDEX" ]; then
          log "发现新短信 ($LAST_INDEX -> $HIGHEST_INDEX)"
           NEW_MESSAGES=0
​
           # 处理每条新短信
           while read -r INDEX; do
               if [ "$INDEX" -gt "$LAST_INDEX" ]; then
                   # 提取短信数据
                  extract_sms_data "$SMS_RESPONSE" "$INDEX"
                   
                   if [ $? -eq 0 ]; then
                       # 格式化日期时间
                       DATE_HUMAN=$(date -d "@$DATETIME" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')
​
                       # 使用飞书卡片格式
                       JSON="{
                          \"msg_type\": \"interactive\",
                          \"card\": {
                              \"header\": {
                                  \"title\": {
                                      \"tag\": \"plain_text\",
                                      \"content\": \"短信通知\"
                                  },
                                  \"template\": \"blue\"
                              },
                              \"elements\": [
                                  {
                                      \"tag\": \"div\",
                                      \"fields\": [
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"lark_md\",
                                                  \"content\": \"📞 **发件人:** $PHONE\"
                                              }
                                          }
                                      ]
                                  },
                                  {
                                      \"tag\": \"div\",
                                      \"fields\": [
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"lark_md\",
                                                  \"content\": \"⏰ **时间:**\"
                                              }
                                          },
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"lark_md\",
                                                  \"content\": \"🔍 **来源:**\"
                                              }
                                          }
                                      ]
                                  },
                                  {
                                      \"tag\": \"div\",
                                      \"fields\": [
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"plain_text\",
                                                  \"content\": \"$DATE_HUMAN\"
                                              }
                                          },
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"plain_text\",
                                                  \"content\": \"$PHONE\"
                                              }
                                          }
                                      ]
                                  },
                                  {
                                      \"tag\": \"hr\"
                                  },
                                  {
                                      \"tag\": \"div\",
                                      \"text\": {
                                          \"tag\": \"lark_md\",
                                          \"content\": \"📄 **内容:**\"
                                      }
                                  },
                                  {
                                      \"tag\": \"div\",
                                      \"text\": {
                                          \"tag\": \"plain_text\",
                                          \"content\": \"$CONTENT\"
                                      }
                                  },
                                  {
                                      \"tag\": \"hr\"
                                  },
                                  {
                                      \"tag\": \"div\",
                                      \"fields\": [
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"lark_md\",
                                                  \"content\": \"📲 短信自动转发系统\"
                                              }
                                          },
                                          {
                                              \"is_short\": true,
                                              \"text\": {
                                                  \"tag\": \"lark_md\",
                                                  \"content\": \"$SIM_INFO | $DEVICE_MODEL\"
                                              }
                                          }
                                      ]
                                  }
                              ]
                          }
                      }"
​
                       # 发送到飞书
                       RESPONSE=$(curl -s -X POST -H "Content-Type: application/json; charset=utf-8" -d "$JSON" "$FEISHU_WEBHOOK_URL")
​
                       if echo "$RESPONSE" | grep -q '"code":0'; then
                          log "转发短信 #$INDEX (来自 $PHONE)"
                           NEW_MESSAGES=$((NEW_MESSAGES + 1))
                       else
                          log "转发短信 #$INDEX 失败"
                       fi
                   fi
               fi
           done < /tmp/sms_indices_sorted.txt
​
           # 更新上次处理的索引
           echo "$HIGHEST_INDEX" > "$LAST_INDEX_FILE"
          log "成功转发 $NEW_MESSAGES 条短信"
​
           # 清理临时文件
           rm -f /tmp/sms_indices.txt /tmp/sms_indices_sorted.txt
       fi
   else
      log "获取短信列表失败,会话可能已过期"
​
       # 尝试重新登录获取新的会话凭证
      get_session_cookie
​
       # 如果登录失败,等待一段时间再重试
       if [ $? -ne 0 ]; then
          log "登录失败,将在5分钟后重试"
           sleep 300
       fi
   fi
​
   # 等待下一次检查
   sleep "$CHECK_INTERVAL"
done

2. 自启动脚本 (custom_init.sh)

#!/bin/sh
# 这个脚本将在系统启动时执行
​
# 启动短信转发服务
/home/scripts/sms_autostart.sh &

3. 服务自启动脚本 (sms_autostart.sh)

#!/bin/sh
# 描述: 短信转发服务自启动脚本
​
# 等待系统完全启动(30秒)
sleep 30
​
# 检查服务是否已经在运行
if ! pgrep -f sms_forward.sh > /dev/null; then
   # 启动短信转发服务
  nohup /home/scripts/sms_forward.sh > /dev/null 2>&1 &
   echo "短信转发服务已启动"
fi

配置系统自启动

在飞猫M20上配置服务自启动有三种方案,推荐使用标准的init.d脚本方式:

方案一:标准Init.d脚本(推荐)

# 创建新的启动脚本
cat > /etc/init.d/sms_forward << 'EOF'
#!/bin/sh
### BEGIN INIT INFO
# Provides:         sms_forward
# Required-Start:   $network
# Required-Stop:    
# Default-Start:     2 3 4 5
# Default-Stop:     0 1 6
# Short-Description: SMS Forwarding Service
### END INIT INFO
​
case "$1" in
 start)
   echo "Starting SMS forwarding service"
  /home/scripts/custom_init.sh &
  ;;
 stop)
   echo "Stopping SMS forwarding service"
   killall sms_forward.sh
  ;;
 restart)
   $0 stop
   sleep 1
   $0 start
  ;;
*)
   echo "Usage: $0 {start|stop|restart}"
   exit 1
  ;;
esac
exit 0
EOF
​
# 设置执行权限
chmod +x /etc/init.d/sms_forward
​
# 创建启动链接
ln -sf /etc/init.d/sms_forward /etc/rc2.d/S99sms_forward
ln -sf /etc/init.d/sms_forward /etc/rc3.d/S99sms_forward
ln -sf /etc/init.d/sms_forward /etc/rc5.d/S99sms_forward

优势:

  • 提供完整的服务管理功能(启动、停止、重启)
  • 可靠的启动顺序控制
  • 适应多种系统运行状态

方案二:修改系统启动脚本

如果您需要更简便的方法,可以修改现有启动脚本:

# 方法1: 修改rcS脚本
if [ -f /etc/init.d/rcS ]; then
 echo "/home/scripts/custom_init.sh &" >> /etc/init.d/rcS
fi
​
# 方法2: 使用rc.local
if [ -f /etc/rc.local ]; then
 sed -i '/exit 0/i \/home\/scripts\/custom_init.sh \&' /etc/rc.local
fi

优势:操作简单,无需创建额外文件

使用注意事项

1. 参数配置说明

使用前必须正确配置以下关键参数:

# 设备API地址
SMS_API_URL="http://192.168.88.1/action/sms_get_sms_list"
LOGIN_URL="http://192.168.88.1/goform/login"
SYNC_URL="http://192.168.88.1/goform/sync"
​
# 飞书配置
FEISHU_WEBHOOK_URL="飞书webhook地址"  # 需要在飞书群组中获取
​
# 设备信息
DEVICE_MODEL="设备名称"  # 如:飞猫M20-客厅
SIM_INFO="手机号"        # 当前设备使用的SIM卡号码
​
# 检查间隔
CHECK_INTERVAL=15       # 建议15-30秒

2. 登录认证参数获取

脚本中使用的登录认证参数需要通过抓包获取:

USERNAME_STATIC="4cc68e3626e5b94602c325f7c4ca5dee"
PASSWORD_STATIC="95bf0786a20922aec868627af48aa872"
REMEMBER_STATIC="d2e6057958b411672c3028b1976a41e1"

获取方法:

  1. 打开浏览器开发者工具(F12)
  2. 登录飞猫M20管理界面(http://192.168.88.1)
  3. 在Network面板中找到login请求
  4. 查看请求数据中的加密值
  5. 替换脚本中对应的值

注意:这些是MD5加密后的值,不是明文账号密码。

3. 飞书Webhook配置

  1. 在飞书群组中添加"群机器人"
  2. 选择"自定义机器人"
  3. 获取Webhook地址
  4. 建议设置关键词过滤,如"短信通知"

脚本工作原理解析

核心功能流程

  1. 会话管理:使用Cookie机制实现自动登录
  2. 数据索引跟踪:记录已处理的最新短信索引,避免重复处理
  3. 数据解析:使用sed/grep等命令解析JSON数据
  4. 消息格式化:生成美观的飞书卡片消息
  5. 异常处理:会话过期自动重连,失败重试机制

技术难点突破

  1. BusyBox限制突破:
    • 在没有Python等高级语言的环境下,使用纯Shell实现复杂功能
    • 利用文件系统实现数据处理,避免内存限制
  2. JSON解析:
    • 通过sed分行和grep匹配实现简单的JSON解析
    • 使用临时文件处理复杂数据结构
  3. 飞书卡片构建:
    • 设计美观的卡片布局,包含发件人、时间、内容等信息
    • 添加表情符号提升可读性

排错指南

常见问题及解决方法

  1. 服务无法启动
    • 检查脚本权限:chmod +x /home/scripts/*.sh
    • 查看日志:cat /tmp/sms_forward.log
  2. 登录失败
    • 验证加密参数是否正确
    • 确认设备IP是否为192.168.88.1
  3. 飞书消息发送失败
    • 验证Webhook地址
    • 检查网络连接
    • 确认飞书机器人状态
  4. 自启动失败
    • 检查init.d脚本权限
    • 验证启动链接是否正确创建
    • 查看系统日志

性能优化建议

  1. 检查间隔调整:根据实际需求调整CHECK_INTERVAL值,平衡实时性和系统负载
  2. 日志管理:定期清理日志文件,避免占用过多存储空间
  3. 内存优化:使用临时文件处理数据,定期清理

安全建议

  1. 修改默认密码:更改设备管理界面和WiFi密码
  2. 限制访问:设置MAC地址过滤,保护设备安全
  3. 数据保护:定期清理设备上的短信记录

总结

通过本文提供的脚本和配置,您可以将飞猫M20随身WiFi设备转变为一个功能强大的短信监控和转发工具。无论是接收验证码、重要通知,还是监控特定号码的短信,这套方案都能满足您的需求。脚本设计考虑了系统资源限制、稳定性和易用性,特别适合需要在移动场景下实时获取短信信息的用户。

希望本文对您有所帮助,如有任何问题,欢迎在评论区留言讨论。

脚本压缩包
下载

提取码:
  • 笔记
  • 编程开发
  • 问题解决
  • BusyBox
  • Shell脚本
  • 短信转发
  • 飞猫M20
等 人表示很赞
261
0

评论

请在登录后评论...
空空如也
推荐 搭建全自动化影视库教程:从零开始打造个人媒体中心 (基于网盘/NAS方案)
前言 服务器有闲置资源,遂折腾一下影视库。本文将介绍如何搭建一个全自动化的影视库系统,从资源获取到观看体验,实现完全自动化的流程。 方案概述 本文将介绍两种方案: 本地 NAS 存储方案 网盘存储方 ...
  • 环境配置
  • 笔记
  • Alist
  • Docker
  • Emby
  • MoviePilot
  • 在线播放
911 0
推荐 利用油猴脚本自动完成Midjourney问卷获取免费快速时长
Midjourney提供了通过完成调查问卷获取免费快速时长的机会,但手动完成这些问卷可能既耗时又重复。本文分享一个简洁高效的Tampermonkey脚本,它能自动随机选择并点击问卷选项,帮助用户快速完成调查获取奖励。脚本设计简单,只需点击一 ...
  • 笔记
  • 编程开发
  • 问题解决
  • AI绘图
  • JavaScript
  • Midjourney
  • Tampermonkey
  • 浏览器脚本
492 0
推荐 在线安全检测工具分享
整理了一些实用的在线安全检测工具,平时下载的绿色软件可以先用这些平台扫描一下。虽然不能百分百防止中毒,但安装前先检测一下,还是能避免很多安全隐患。 ...
  • 环境配置
  • 笔记
  • 在线工具
  • 安全工具
  • 安全防护
  • 病毒扫描
  • 软件检测
724 0
推荐 自建RustDesk远程桌面服务器:Docker部署完整指南
RustDesk是一款开源的远程桌面解决方案,相比市面上其他远程控制软件,它提供了更好的用户体验和完全的数据控制权。本文详细介绍如何使用Docker自建RustDesk服务器,包括环境准备、Docker配置文件创建、服务启动、密钥获取、防火 ...
  • 开源推荐
  • 环境配置
  • 笔记
  • 资源
  • 问题解决
  • Docker
  • RustDesk
  • 远程控制
  • 远程桌面
463 0
推荐 Shell脚本完全指南:从入门到精通的Linux命令行编程
本教程提供了Shell脚本编程的全面指南,从Shell基础概念开始,详细介绍了变量类型、字符串操作、数组处理和参数传递等核心知识。教程深入讲解了条件语句、循环结构和函数定义等流程控制机制,并涵盖了正则表达式、错误处理、调试技巧和进程管理等高 ...
  • 学习资料
  • 笔记
  • 编程开发
  • 资源
  • Bash
  • Linux
  • shell
  • 命令行
  • 文本处理
261 0

推荐栏目

  • 笔记
  • 资源
  • 编程开发
  • 问题解决
  • 环境配置
  • 开源推荐
  • 随笔
  • 生活随记
  • 软件推荐

推荐标签

  • Docker
  • AI绘图
  • JavaScript
  • Tampermonkey
  • Midjourney
  • 开源项目
  • 在线播放
  • 影音系统
  • 自动填表
    暂无内容
Copyright © 2025 云边日落. All rights reserved. Designed by nicetheme.
  • 随笔
    • 思考感悟
    • 生活随记
    • 阅读笔记
  • 笔记
    • 环境配置
    • 编程开发
    • 问题解决
  • 资源
    • 学习资料
    • 开源推荐
    • 软件推荐
  • 友联
  • 关于
欢迎回来
账号注册 忘记密码?
其他登录方式
欢迎回来
账号注册 忘记密码?
其他登录方式
微信扫码登录
未注册的微信号将自动创建账号
扫码回复关键词「登录」获取验证码
其他登录方式
免费注册
其他登录方式
重设密码
返回登录