├── .github └── workflows │ └── build-go.yml ├── .gitignore ├── CloudFlare.md ├── Dockerfile ├── LICENSE ├── README.md ├── README_en.md ├── api └── vercel.go ├── assets ├── assets.go └── templates │ ├── files.tmpl │ ├── footer.tmpl │ ├── header.tmpl │ ├── images.tmpl │ └── pwd.tmpl ├── conf └── conf.go ├── control └── control.go ├── get.sh ├── go.mod ├── go.sum ├── main.go ├── utils └── utils.go └── vercel.json /.github/workflows/build-go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | release: 5 | types: [ "created" ] 6 | 7 | jobs: 8 | build_and_upload_assets: 9 | permissions: write-all 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v3 14 | 15 | - name: Set up Go 16 | uses: actions/setup-go@v3 17 | with: 18 | go-version: 1.17.2 19 | 20 | - name: Update go.mod to use Go 1.17 21 | run: | 22 | sed -i 's/go 1.20/go 1.17/' go.mod 23 | 24 | - name: Download dependencies 25 | run: go mod tidy 26 | 27 | - name: Build Linux arm64 28 | run: | 29 | CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o tgState main.go 30 | 31 | - name: Zip Linux amd64 32 | run: | 33 | sudo apt-get install -y zip 34 | zip tgState_arm64.zip tgState 35 | 36 | - name: Delete tgState arm64 37 | run: | 38 | rm tgState 39 | 40 | - name: Build Linux amd64 41 | run: | 42 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o tgState main.go 43 | 44 | - name: Zip Linux amd64 45 | run: | 46 | sudo apt-get install -y zip 47 | zip tgState.zip tgState 48 | 49 | - name: Upload server asset 50 | uses: actions/upload-release-asset@v1 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | with: 54 | upload_url: ${{ github.event.release.upload_url }} 55 | asset_path: ./tgState.zip 56 | asset_name: tgState.zip 57 | asset_content_type: application/zip 58 | 59 | - name: Upload server asset 60 | uses: actions/upload-release-asset@v1 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 63 | with: 64 | upload_url: ${{ github.event.release.upload_url }} 65 | asset_path: ./tgState_arm64.zip 66 | asset_name: tgState_arm64.zip 67 | asset_content_type: application/zip 68 | 69 | - name: Set up Docker Buildx 70 | uses: docker/setup-buildx-action@v1 71 | 72 | - name: Log in to Docker Hub 73 | uses: docker/login-action@v1 74 | with: 75 | username: ${{ secrets.DOCKERHUB_USERNAME }} 76 | password: ${{ secrets.DOCKERHUB_TOKEN }} 77 | 78 | - name: Build and push Docker image 79 | uses: docker/build-push-action@v2 80 | with: 81 | context: . 82 | push: true 83 | tags: csznet/tgstate:latest 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---> Go 2 | # If you prefer the allow list template instead of the deny list, see community template: 3 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 4 | # 5 | # Binaries for programs and plugins 6 | *.exe 7 | *.exe~ 8 | *.dll 9 | *.so 10 | *.dylib 11 | # Test binary, built with `go test -c` 12 | *.test 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | # Go workspace file 18 | go.work 19 | #diy 20 | main 21 | tgstate 22 | mk.txt 23 | .idea/* 24 | .vscode/* 25 | tmp/* 26 | .air.toml 27 | .vercel 28 | -------------------------------------------------------------------------------- /CloudFlare.md: -------------------------------------------------------------------------------- 1 | 进阶指南 2 | == 3 | 4 | Vercel 5 | -- 6 | 7 | vercel默认域名部分地区会有阻断,建议添加自定义域名 8 | 使用cname解析到```cname-china.vercel-dns.com``` 9 | 10 | CloudFlare 11 | -- 12 | **SSL证书访问** 13 | 目的:解决开启SSL&Cloudflare CDN后重定向过多问题 14 | 设置路径:域名->SSL/TLS->Overview 15 | 设置为Full(strict) 16 |  17 | 18 | **完全缓存图片** 19 | 目的:加快访问速度,减少api请求次数 20 | 设置路径:域名->Rules->Page Rules->Create Page Rule 21 | 给```/d/*```设置缓存所有,如下 22 |  23 |  24 | 25 | **控制请求速率** 26 | 目的:防止刷上传 27 | 设置路径:域名->Security->WAF->Rate limiting rules 28 | 建议给```/api```限制在10s不超过2次请求,如下 29 |  30 | 31 | **开启Always Online** 32 | 目的:当服务宕机后,图片正常访问 33 | 设置路径:域名->Caching->Configuration->Always Online 34 |  -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 使用官方的 Ubuntu 基础镜像 2 | FROM ubuntu:latest 3 | 4 | # 安装 ca-certificates 包,用于更新根证书 5 | RUN apt-get update && apt-get install -y ca-certificates 6 | 7 | # 将编译好的 server 和 client 二进制文件复制到容器中 8 | COPY tgState /app/tgState 9 | 10 | # 设置工作目录 11 | WORKDIR /app 12 | 13 | # 设置暴露的端口 14 | EXPOSE 8088 15 | 16 | # 设置容器启动时要执行的命令 17 | CMD [ "/app/tgState" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 csznet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tgState 2 | == 3 | 4 | [English](https://github.com/csznet/tgState/blob/main/README_en.md) 5 | 6 | 一款以Telegram作为储存的文件外链系统 7 | 8 | 不限制文件大小和格式 9 | 10 | 可以作为telegram图床,也可以作为telegram网盘使用。 11 | 12 | 支持web上传文件和telegram直接上传 13 | 14 | 搭配CLoudFlare使用:https://github.com/csznet/tgState/blob/main/CloudFlare.md 15 | 16 | 如有疑惑,可以咨询TG @tgstate123 17 | 18 | # 演示 19 | 20 | https://tgstate.vercel.app 21 | 22 | 搭建在vercel,资源限制,大于5MB的文件不支持 23 | 24 | 演示图片: 25 | 26 |  27 | 28 | # 参数说明 29 | 30 | 必填参数 31 | 32 | - target 33 | - token 34 | 35 | 可选参数 36 | 37 | - pass 38 | - mode 39 | - url 40 | - port 41 | 42 | ## target 43 | 44 | 目标可为频道、群组、个人 45 | 46 | 当目标为频道时,需要将Bot拉入频道作为管理员,公开频道并自定义频道Link,target值填写Link,如@xxxx 47 | 48 | 当目标为群组时,需要将Bot拉入群组,公开群组并自定义群组Link,target值填写Link,如@xxxx 49 | 50 | 当目标为个人时,则为telegram id(@getmyid_bot获取) 51 | 52 | ## token 53 | 54 | 填写你的bot token 55 | 56 | ## pass 57 | 58 | 填写访问密码,如不需要,直接填写```none```即可 59 | 60 | ## mode 61 | 62 | - ```p``` 代表网盘模式运行,不限制上传后缀 63 | - ```m``` 在p模式的基础上关闭网页上传,可私聊进行上传(如果target是个人,则只支持指定用户进行私聊上传 64 | 65 | ## url 66 | 67 | bot获取FileID的前置域名地址自动补充及api返回完整url的补充 68 | 69 | ## port 70 | 71 | 自定义运行端口 72 | 73 | # 管理 74 | 75 | ## 获取FIleID 76 | 77 | 对bot聊天中的文件引用并回复```get```可以获取FileID,搭建地址+获取的path即可访问资源 78 | 79 | 如果配置了url参数,会直接返回完整的地址 80 | 81 |  82 | 83 | # 部署 84 | 85 | ## 二进制 86 | 87 | Linux amd64下载 88 | 89 | ``` 90 | wget https://github.com/csznet/tgState/releases/latest/download/tgState.zip && unzip tgState.zip && rm tgState.zip 91 | ``` 92 | 93 | Linux arm64下载 94 | 95 | ``` 96 | wget https://github.com/csznet/tgState/releases/latest/download/tgState_arm64.zip && unzip tgState_arm64.zip && rm tgState_arm64.zip 97 | ``` 98 | 99 | Linux 一键脚本 100 | 101 | ``` 102 | bash -c "$(curl -fsSL https://raw.githubusercontent.com/csznet/tgState/main/get.sh)" 103 | ``` 104 | 105 | 106 | **使用方法** 107 | 108 | ``` 109 | ./tgState 参数 110 | ``` 111 | 112 | **例子** 113 | ``` 114 | ./tgState -token xxxx -target @xxxx 115 | ``` 116 | 117 | **后台运行** 118 | 119 | ``` 120 | nohup ./tgState 参数 & 121 | ``` 122 | 123 | ## Docker 124 | 125 | pull镜像 126 | ``` 127 | docker pull csznet/tgstate:latest 128 | ``` 129 | 130 | 启动 131 | ``` 132 | docker run -d -p 8088:8088 --name tgstate 参数 --net=host csznet/tgstate:latest 133 | ``` 134 | 其中docker的参数需要设置为环境变量 135 | 136 | 开机自启需要加上 137 | ``` 138 | --restart always 139 | ``` 140 | 141 | 142 | **例子** 143 | ``` 144 | docker run -d -p 8088:8088 --name tgstate -e token=token -e target=@target -e mode=p --net=host csznet/tgstate:latest 145 | ``` 146 | 147 | ## Vercel 148 | 149 | 不支持大于5mb文件,不支持tg获取文件路径 150 | 151 | [点我传送至Vercel配置页面](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fcsznet%2FtgState&env=token&env=target&env=pass&env=mode&env=url&project-name=tgState&repository-name=tgState) 152 | 153 | # API说明 154 | 155 | POST方法到路径```/api``` 156 | 157 | 表单传输,字段名为image,内容为二进制数据 158 | 159 | 当设置访问密码时,直接将密码加入url参数pass中,如密码为123: 160 | 161 | ``` 162 | /api?pass=123 163 | ``` 164 | 165 | 返回示例: 166 | 167 | ```json 168 | {"code": 1, "message": "/d/xxx","url":"xxx"} 169 | ``` 170 | 171 | json格式的`url`默认返回tgState的`url`参数+访问路径,如果只得到了路径则需要自行设置`url`参数 172 | 173 | picgo-plugin-web-uploader填写说明: 174 | 175 | POST参数名:`image` 176 | 177 | JSON路径:`url` 178 | 179 |  180 | 181 | 182 | -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # tgState 2 | == 3 | 4 | [中文](https://github.com/csznet/tgState/blob/main/README.md) 5 | 6 | A file external link system using Telegram as storage. 7 | 8 | No restrictions on file size and format. 9 | 10 | Can be used as a Telegram image hosting service or a Telegram cloud drive. 11 | 12 | Supports web and Telegram direct file uploads. 13 | 14 | Use with CloudFlare: https://github.com/csznet/tgState/blob/main/CloudFlare.md 15 | 16 | For any questions, consult TG @tgstate123 17 | 18 | # Demo 19 | 20 | https://tgstate.vercel.app / https://tgstate.ikun123.com/ 21 | 22 | Hosted on Vercel, resource limitations - files larger than 5MB are not supported. 23 | 24 | Demo image: 25 | 26 |  27 | 28 | # Parameter Description 29 | 30 | Mandatory parameters: 31 | 32 | - target 33 | - token 34 | 35 | Optional parameters: 36 | 37 | - pass 38 | - mode 39 | - url 40 | - port 41 | 42 | ## target 43 | 44 | The target can be a channel, group, or individual. 45 | 46 | When the target is a channel, the bot needs to be added to the channel as an administrator, make the channel public, and customize the channel link. The target value should be filled with the link, such as @xxxx. 47 | 48 | When the target is a group, the bot needs to be added to the group, make the group public, and customize the group link. The target value should be filled with the link, such as @xxxx. 49 | 50 | When the target is an individual, it is the Telegram ID (obtained from @getmyid_bot). 51 | 52 | ## token 53 | 54 | Fill in your bot token. 55 | 56 | ## pass 57 | 58 | Fill in the access password. If not needed, fill in ```none``` directly. 59 | 60 | ## mode 61 | 62 | - ```p``` represents running in cloud drive mode, with no restriction on uploaded suffixes. 63 | - ```m``` On top of the p mode, web upload is disabled, and upload can be done via private chat (if the target is an individual, only specified users can upload via private chat). 64 | 65 | ## url 66 | 67 | The pre-domain address that bot obtains FileID is automatically filled in. 68 | 69 | ## port 70 | 71 | Customize the running port. 72 | 73 | # Management 74 | 75 | ## Get FIleID 76 | 77 | Replying with ```get``` to the file reference in the bot's chat can get the FileID. Access the resource by combining the built address and the obtained path. 78 | 79 | If the url parameter is configured, the complete address will be returned directly. 80 | 81 |  82 | 83 | # Deployment 84 | 85 | ## Binary 86 | 87 | Download for Linux amd64 88 | 89 | ``` 90 | wget https://github.com/csznet/tgState/releases/latest/download/tgState.zip && unzip tgState.zip && rm tgState.zip 91 | ``` 92 | 93 | Download for Linux arm64 94 | 95 | ``` 96 | wget https://github.com/csznet/tgState/releases/latest/download/tgState_arm64.zip && unzip tgState_arm64.zip && rm tgState_arm64.zip 97 | ``` 98 | 99 | **Usage** 100 | 101 | ```./tgState parameters``` 102 | 103 | **Example** 104 | 105 | ```./tgState -token xxxx -target @xxxx``` 106 | 107 | **Run in the background** 108 | 109 | ```nohup ./tgState parameters &``` 110 | 111 | ## Docker 112 | 113 | Pull the image 114 | 115 | ```docker pull csznet/tgstate:latest``` 116 | 117 | 118 | Start 119 | 120 | ``` 121 | docker run -d -p 8088:8088 --name tgstate parameters --net=host csznet/tgstate:latest 122 | ``` 123 | 124 | Where docker parameters need to be set as environment variables. 125 | 126 | **Example** 127 | 128 | ``` 129 | docker run -d -p 8088:8088 --name tgstate -e token=aaa -e target=@bbb --net=host csznet/tgstate:latest 130 | ``` 131 | 132 | ## Vercel 133 | 134 | Does not support files larger than 5MB and does not support Telegram in getting file paths. 135 | 136 | [Click here to go to the Vercel configuration page](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fcsznet%2FtgState&env=token&env=target&env=pass&env=mode&project-name=tgState&repository-name=tgState) 137 | 138 | # API Description 139 | 140 | POST method to the path ```/api``` 141 | 142 | Form transmission, field name is image, content is binary data. 143 | -------------------------------------------------------------------------------- /api/vercel.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | "strings" 7 | 8 | "csz.net/tgstate/conf" 9 | "csz.net/tgstate/control" 10 | ) 11 | 12 | func Vercel(w http.ResponseWriter, r *http.Request) { 13 | conf.BotToken = os.Getenv("token") 14 | conf.ChannelName = os.Getenv("target") 15 | conf.Pass = os.Getenv("pass") 16 | conf.Mode = os.Getenv("mode") 17 | conf.BaseUrl = os.Getenv("url") 18 | // 获取请求路径 19 | path := r.URL.Path 20 | // 如果请求路径以 "/img/" 开头 21 | if strings.HasPrefix(path, conf.FileRoute) { 22 | control.D(w, r) 23 | return // 结束处理,确保不执行默认处理 24 | } 25 | switch path { 26 | case "/api": 27 | // 调用 control 包中的 UploadImageAPI 处理函数 28 | control.Middleware(control.UploadImageAPI)(w, r) 29 | case "/pwd": 30 | control.Pwd(w, r) 31 | default: 32 | control.Middleware(control.Index)(w, r) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/assets.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import "embed" 4 | 5 | var ( 6 | //go:embed templates 7 | Templates embed.FS 8 | ) 9 | -------------------------------------------------------------------------------- /assets/templates/files.tmpl: -------------------------------------------------------------------------------- 1 | {{template "public/header" .}} 2 |