Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4ea8787c9 | |||
a4de04528a | |||
f60aae7499 | |||
de8f9e9eee | |||
cace9db12f | |||
ec2fb82836 | |||
afcfbf02ea | |||
cad04e07dd | |||
30f732138c | |||
04034bd03b | |||
6ec9a8d4c7 |
2
.github/workflows/issue_question.yml
vendored
2
.github/workflows/issue_question.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
if: github.event.label.name == 'question'
|
if: github.event.label.name == 'question'
|
||||||
steps:
|
steps:
|
||||||
- name: Create comment
|
- name: Create comment
|
||||||
uses: actions-cool/issues-helper@v3.4.0
|
uses: actions-cool/issues-helper@v3.5.0
|
||||||
with:
|
with:
|
||||||
actions: 'create-comment'
|
actions: 'create-comment'
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
English | [中文](./README_cn.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
|
English | [中文](./README_cn.md)| [日本語](./README_ja.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -112,8 +112,7 @@ https://alist.nn.ci/guide/sponsor.html
|
|||||||
### Special sponsors
|
### Special sponsors
|
||||||
|
|
||||||
- [亚洲云 - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商](https://www.asiayun.com/aff/QQCOOQKZ) (sponsored Chinese API server)
|
- [亚洲云 - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商](https://www.asiayun.com/aff/QQCOOQKZ) (sponsored Chinese API server)
|
||||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
|
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||||
- [KinhDown 百度云盘不限速下载!永久免费!已稳定运行3年!非常可靠!Q群 -> 786799372](https://kinhdown.com)
|
|
||||||
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
|
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[English](./README.md) | 中文 | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
|
[English](./README.md) | 中文 | [日本語](./README_ja.md) | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
|
|
||||||
@ -110,8 +110,7 @@ AList 是一个开源软件,如果你碰巧喜欢这个项目,并希望我
|
|||||||
### 特别赞助
|
### 特别赞助
|
||||||
|
|
||||||
- [亚洲云 - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商](https://www.asiayun.com/aff/QQCOOQKZ) (国内API服务器赞助)
|
- [亚洲云 - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商](https://www.asiayun.com/aff/QQCOOQKZ) (国内API服务器赞助)
|
||||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
|
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||||
- [KinhDown 百度云盘不限速下载!永久免费!已稳定运行3年!非常可靠!Q群 -> 786799372](https://kinhdown.com)
|
|
||||||
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
|
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
|
||||||
|
|
||||||
## 贡献者
|
## 贡献者
|
||||||
|
137
README_ja.md
Normal file
137
README_ja.md
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<div align="center">
|
||||||
|
<a href="https://alist.nn.ci"><img height="100px" alt="logo" src="https://cdn.jsdelivr.net/gh/alist-org/logo@main/logo.svg"/></a>
|
||||||
|
<p><em>🗂️Gin と Solidjs による、複数のストレージをサポートするファイルリストプログラム。</em></p>
|
||||||
|
<div>
|
||||||
|
<a href="https://goreportcard.com/report/github.com/alist-org/alist/v3">
|
||||||
|
<img src="https://goreportcard.com/badge/github.com/alist-org/alist/v3" alt="latest version" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Xhofe/alist/blob/main/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/Xhofe/alist" alt="License" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Xhofe/alist/actions?query=workflow%3ABuild">
|
||||||
|
<img src="https://img.shields.io/github/actions/workflow/status/Xhofe/alist/build.yml?branch=main" alt="Build status" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Xhofe/alist/releases">
|
||||||
|
<img src="https://img.shields.io/github/release/Xhofe/alist" alt="latest version" />
|
||||||
|
</a>
|
||||||
|
<a title="Crowdin" target="_blank" href="https://crwd.in/alist">
|
||||||
|
<img src="https://badges.crowdin.net/alist/localized.svg">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://github.com/Xhofe/alist/discussions">
|
||||||
|
<img src="https://img.shields.io/github/discussions/Xhofe/alist?color=%23ED8936" alt="discussions" />
|
||||||
|
</a>
|
||||||
|
<a href="https://discord.gg/F4ymsH4xv2">
|
||||||
|
<img src="https://img.shields.io/discord/1018870125102895134?logo=discord" alt="discussions" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Xhofe/alist/releases">
|
||||||
|
<img src="https://img.shields.io/github/downloads/Xhofe/alist/total?color=%239F7AEA&logo=github" alt="Downloads" />
|
||||||
|
</a>
|
||||||
|
<a href="https://hub.docker.com/r/xhofe/alist">
|
||||||
|
<img src="https://img.shields.io/docker/pulls/xhofe/alist?color=%2348BB78&logo=docker&label=pulls" alt="Downloads" />
|
||||||
|
</a>
|
||||||
|
<a href="https://alist.nn.ci/guide/sponsor.html">
|
||||||
|
<img src="https://img.shields.io/badge/%24-sponsor-F87171.svg" alt="sponsor" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[English](./README.md) | [中文](./README_cn.md) | 日本語 | [Contributing](./CONTRIBUTING.md) | [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
|
## 特徴
|
||||||
|
|
||||||
|
- [x] マルチストレージ
|
||||||
|
- [x] ローカルストレージ
|
||||||
|
- [x] [Aliyundrive](https://www.aliyundrive.com/)
|
||||||
|
- [x] OneDrive / Sharepoint ([グローバル](https://www.office.com/), [cn](https://portal.partner.microsoftonline.cn),de,us)
|
||||||
|
- [x] [189cloud](https://cloud.189.cn) (Personal, Family)
|
||||||
|
- [x] [GoogleDrive](https://drive.google.com/)
|
||||||
|
- [x] [123pan](https://www.123pan.com/)
|
||||||
|
- [x] FTP / SFTP
|
||||||
|
- [x] [PikPak](https://www.mypikpak.com/)
|
||||||
|
- [x] [S3](https://aws.amazon.com/s3/)
|
||||||
|
- [x] [Seafile](https://seafile.com/)
|
||||||
|
- [x] [UPYUN Storage Service](https://www.upyun.com/products/file-storage)
|
||||||
|
- [x] WebDav(Support OneDrive/SharePoint without API)
|
||||||
|
- [x] Teambition([China](https://www.teambition.com/ ),[International](https://us.teambition.com/ ))
|
||||||
|
- [x] [Mediatrack](https://www.mediatrack.cn/)
|
||||||
|
- [x] [139yun](https://yun.139.com/) (Personal, Family)
|
||||||
|
- [x] [YandexDisk](https://disk.yandex.com/)
|
||||||
|
- [x] [BaiduNetdisk](http://pan.baidu.com/)
|
||||||
|
- [x] [Terabox](https://www.terabox.com/main)
|
||||||
|
- [x] [UC](https://drive.uc.cn)
|
||||||
|
- [x] [Quark](https://pan.quark.cn)
|
||||||
|
- [x] [Thunder](https://pan.xunlei.com)
|
||||||
|
- [x] [Lanzou](https://www.lanzou.com/)
|
||||||
|
- [x] [Aliyundrive share](https://www.aliyundrive.com/)
|
||||||
|
- [x] [Google photo](https://photos.google.com/)
|
||||||
|
- [x] [Mega.nz](https://mega.nz)
|
||||||
|
- [x] [Baidu photo](https://photo.baidu.com/)
|
||||||
|
- [x] SMB
|
||||||
|
- [x] [115](https://115.com/)
|
||||||
|
- [X] Cloudreve
|
||||||
|
- [x] [Dropbox](https://www.dropbox.com/)
|
||||||
|
- [x] デプロイが簡単で、すぐに使える
|
||||||
|
- [x] ファイルプレビュー (PDF, マークダウン, コード, プレーンテキスト, ...)
|
||||||
|
- [x] ギャラリーモードでの画像プレビュー
|
||||||
|
- [x] ビデオとオーディオのプレビュー、歌詞と字幕のサポート
|
||||||
|
- [x] Office ドキュメントのプレビュー (docx, pptx, xlsx, ...)
|
||||||
|
- [x] `README.md` のプレビューレンダリング
|
||||||
|
- [x] ファイルのパーマリンクコピーと直接ダウンロード
|
||||||
|
- [x] ダークモード
|
||||||
|
- [x] 国際化
|
||||||
|
- [x] 保護されたルート (パスワード保護と認証)
|
||||||
|
- [x] WebDav (詳細は https://alist.nn.ci/guide/webdav.html を参照)
|
||||||
|
- [x] [Docker デプロイ](https://hub.docker.com/r/xhofe/alist)
|
||||||
|
- [x] Cloudflare ワーカープロキシ
|
||||||
|
- [x] ファイル/フォルダパッケージのダウンロード
|
||||||
|
- [x] ウェブアップロード(訪問者にアップロードを許可できる), 削除, mkdir, 名前変更, 移動, コピー
|
||||||
|
- [x] オフラインダウンロード
|
||||||
|
- [x] 二つのストレージ間でファイルをコピー
|
||||||
|
|
||||||
|
## ドキュメント
|
||||||
|
|
||||||
|
<https://alist.nn.ci/>
|
||||||
|
|
||||||
|
## デモ
|
||||||
|
|
||||||
|
<https://al.nn.ci>
|
||||||
|
|
||||||
|
## ディスカッション
|
||||||
|
|
||||||
|
一般的なご質問は[ディスカッションフォーラム](https://github.com/Xhofe/alist/discussions)をご利用ください。**問題はバグレポートと機能リクエストのみです。**
|
||||||
|
|
||||||
|
## スポンサー
|
||||||
|
|
||||||
|
AList はオープンソースのソフトウェアです。もしあなたがこのプロジェクトを気に入ってくださり、続けて欲しいと思ってくださるなら、ぜひスポンサーになってくださるか、1口でも寄付をしてくださるようご検討ください!すべての愛とサポートに感謝します:
|
||||||
|
https://alist.nn.ci/guide/sponsor.html
|
||||||
|
|
||||||
|
### スペシャルスポンサー
|
||||||
|
|
||||||
|
- [亚洲云 - 高防服务器|服务器租用|福州高防|广东电信|香港服务器|美国服务器|海外服务器 - 国内靠谱的企业级云计算服务提供商](https://www.asiayun.com/aff/QQCOOQKZ) (sponsored Chinese API server)
|
||||||
|
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||||
|
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
|
||||||
|
|
||||||
|
## コントリビューター
|
||||||
|
|
||||||
|
これらの素晴らしい人々に感謝します:
|
||||||
|
|
||||||
|
[](https://github.com/alist-org/alist/graphs/contributors)
|
||||||
|
|
||||||
|
## ライセンス
|
||||||
|
|
||||||
|
`AList` は AGPL-3.0 ライセンスの下でライセンスされたオープンソースソフトウェアです。
|
||||||
|
|
||||||
|
## 免責事項
|
||||||
|
- このプログラムはフリーでオープンソースのプロジェクトです。ネットワークディスク上でファイルを共有するように設計されており、golang のダウンロードや学習に便利です。利用にあたっては関連法規を遵守し、悪用しないようお願いします;
|
||||||
|
- このプログラムは、公式インターフェースの動作を破壊することなく、公式 sdk/インターフェースを呼び出すことで実装されています;
|
||||||
|
- このプログラムは、302リダイレクト/トラフィック転送のみを行い、いかなるユーザーデータも傍受、保存、改ざんしません;
|
||||||
|
- このプログラムを使用する前に、アカウントの禁止、ダウンロード速度の制限など、対応するリスクを理解し、負担する必要があります;
|
||||||
|
- もし侵害があれば、[メール](mailto:i@nn.ci)で私に連絡してください。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> [@Blog](https://nn.ci/) · [@GitHub](https://github.com/Xhofe) · [@TelegramGroup](https://t.me/alist_chat) · [@Discord](https://discord.gg/F4ymsH4xv2)
|
@ -34,6 +34,25 @@ func (d *Pan123) getS3PreSignedUrls(ctx context.Context, upReq *UploadResp, star
|
|||||||
return &s3PreSignedUrls, nil
|
return &s3PreSignedUrls, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Pan123) getS3Auth(ctx context.Context, upReq *UploadResp, start, end int) (*S3PreSignedURLs, error) {
|
||||||
|
data := base.Json{
|
||||||
|
"StorageNode": upReq.Data.StorageNode,
|
||||||
|
"bucket": upReq.Data.Bucket,
|
||||||
|
"key": upReq.Data.Key,
|
||||||
|
"partNumberEnd": end,
|
||||||
|
"partNumberStart": start,
|
||||||
|
"uploadId": upReq.Data.UploadId,
|
||||||
|
}
|
||||||
|
var s3PreSignedUrls S3PreSignedURLs
|
||||||
|
_, err := d.request(S3Auth, http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(data).SetContext(ctx)
|
||||||
|
}, &s3PreSignedUrls)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &s3PreSignedUrls, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Pan123) completeS3(ctx context.Context, upReq *UploadResp, file model.FileStreamer, isMultipart bool) error {
|
func (d *Pan123) completeS3(ctx context.Context, upReq *UploadResp, file model.FileStreamer, isMultipart bool) error {
|
||||||
data := base.Json{
|
data := base.Json{
|
||||||
"StorageNode": upReq.Data.StorageNode,
|
"StorageNode": upReq.Data.StorageNode,
|
||||||
@ -51,11 +70,17 @@ func (d *Pan123) completeS3(ctx context.Context, upReq *UploadResp, file model.F
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.FileStreamer, reader io.Reader, up driver.UpdateProgress) error {
|
func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.FileStreamer, reader io.Reader, up driver.UpdateProgress) error {
|
||||||
chunkSize := int64(1024 * 1024 * 5)
|
chunkSize := int64(1024 * 1024 * 16)
|
||||||
// fetch s3 pre signed urls
|
// fetch s3 pre signed urls
|
||||||
chunkCount := int(math.Ceil(float64(file.GetSize()) / float64(chunkSize)))
|
chunkCount := int(math.Ceil(float64(file.GetSize()) / float64(chunkSize)))
|
||||||
// upload 10 chunks each batch
|
// only 1 batch is allowed
|
||||||
batchSize := 10
|
isMultipart := chunkCount > 1
|
||||||
|
batchSize := 1
|
||||||
|
getS3UploadUrl := d.getS3Auth
|
||||||
|
if isMultipart {
|
||||||
|
batchSize = 10
|
||||||
|
getS3UploadUrl = d.getS3PreSignedUrls
|
||||||
|
}
|
||||||
for i := 1; i <= chunkCount; i += batchSize {
|
for i := 1; i <= chunkCount; i += batchSize {
|
||||||
if utils.IsCanceled(ctx) {
|
if utils.IsCanceled(ctx) {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
@ -65,7 +90,7 @@ func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.Fi
|
|||||||
if end > chunkCount+1 {
|
if end > chunkCount+1 {
|
||||||
end = chunkCount + 1
|
end = chunkCount + 1
|
||||||
}
|
}
|
||||||
s3PreSignedUrls, err := d.getS3PreSignedUrls(ctx, upReq, start, end)
|
s3PreSignedUrls, err := getS3UploadUrl(ctx, upReq, start, end)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -78,7 +103,7 @@ func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.Fi
|
|||||||
if j == chunkCount {
|
if j == chunkCount {
|
||||||
curSize = file.GetSize() - (int64(chunkCount)-1)*chunkSize
|
curSize = file.GetSize() - (int64(chunkCount)-1)*chunkSize
|
||||||
}
|
}
|
||||||
err = d.uploadS3Chunk(ctx, upReq, s3PreSignedUrls, j, end, io.LimitReader(reader, chunkSize), curSize, false)
|
err = d.uploadS3Chunk(ctx, upReq, s3PreSignedUrls, j, end, io.LimitReader(reader, chunkSize), curSize, false, getS3UploadUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -89,7 +114,7 @@ func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.Fi
|
|||||||
return d.completeS3(ctx, upReq, file, chunkCount > 1)
|
return d.completeS3(ctx, upReq, file, chunkCount > 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Pan123) uploadS3Chunk(ctx context.Context, upReq *UploadResp, s3PreSignedUrls *S3PreSignedURLs, cur, end int, reader io.Reader, curSize int64, retry bool) error {
|
func (d *Pan123) uploadS3Chunk(ctx context.Context, upReq *UploadResp, s3PreSignedUrls *S3PreSignedURLs, cur, end int, reader io.Reader, curSize int64, retry bool, getS3UploadUrl func(ctx context.Context, upReq *UploadResp, start int, end int) (*S3PreSignedURLs, error)) error {
|
||||||
uploadUrl := s3PreSignedUrls.Data.PreSignedUrls[strconv.Itoa(cur)]
|
uploadUrl := s3PreSignedUrls.Data.PreSignedUrls[strconv.Itoa(cur)]
|
||||||
if uploadUrl == "" {
|
if uploadUrl == "" {
|
||||||
return fmt.Errorf("upload url is empty, s3PreSignedUrls: %+v", s3PreSignedUrls)
|
return fmt.Errorf("upload url is empty, s3PreSignedUrls: %+v", s3PreSignedUrls)
|
||||||
@ -111,13 +136,13 @@ func (d *Pan123) uploadS3Chunk(ctx context.Context, upReq *UploadResp, s3PreSign
|
|||||||
return fmt.Errorf("upload s3 chunk %d failed, status code: %d", cur, res.StatusCode)
|
return fmt.Errorf("upload s3 chunk %d failed, status code: %d", cur, res.StatusCode)
|
||||||
}
|
}
|
||||||
// refresh s3 pre signed urls
|
// refresh s3 pre signed urls
|
||||||
newS3PreSignedUrls, err := d.getS3PreSignedUrls(ctx, upReq, cur, end)
|
newS3PreSignedUrls, err := getS3UploadUrl(ctx, upReq, cur, end)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s3PreSignedUrls.Data.PreSignedUrls = newS3PreSignedUrls.Data.PreSignedUrls
|
s3PreSignedUrls.Data.PreSignedUrls = newS3PreSignedUrls.Data.PreSignedUrls
|
||||||
// retry
|
// retry
|
||||||
return d.uploadS3Chunk(ctx, upReq, s3PreSignedUrls, cur, end, reader, curSize, true)
|
return d.uploadS3Chunk(ctx, upReq, s3PreSignedUrls, cur, end, reader, curSize, true, getS3UploadUrl)
|
||||||
}
|
}
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
body, err := io.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package _123
|
package _123
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/drivers/base"
|
"github.com/alist-org/alist/v3/drivers/base"
|
||||||
"github.com/alist-org/alist/v3/pkg/utils"
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
@ -17,7 +21,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
AApi = "https://www.123pan.com/a/api"
|
AApi = "https://www.123pan.com/a/api"
|
||||||
BApi = "https://www.123pan.com/b/api"
|
BApi = "https://www.123pan.com/b/api"
|
||||||
MainApi = AApi
|
MainApi = BApi
|
||||||
SignIn = MainApi + "/user/sign_in"
|
SignIn = MainApi + "/user/sign_in"
|
||||||
Logout = MainApi + "/user/logout"
|
Logout = MainApi + "/user/logout"
|
||||||
UserInfo = MainApi + "/user/info"
|
UserInfo = MainApi + "/user/info"
|
||||||
@ -33,6 +37,7 @@ const (
|
|||||||
S3Auth = MainApi + "/file/s3_upload_object/auth"
|
S3Auth = MainApi + "/file/s3_upload_object/auth"
|
||||||
UploadCompleteV2 = MainApi + "/file/upload_complete/v2"
|
UploadCompleteV2 = MainApi + "/file/upload_complete/v2"
|
||||||
S3Complete = MainApi + "/file/s3_complete_multipart_upload"
|
S3Complete = MainApi + "/file/s3_complete_multipart_upload"
|
||||||
|
AuthKeySalt = "8-8D$sL8gPjom7bk#cY"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *Pan123) login() error {
|
func (d *Pan123) login() error {
|
||||||
@ -70,6 +75,20 @@ func (d *Pan123) login() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func authKey(reqUrl string) (*string, error) {
|
||||||
|
reqURL, err := url.Parse(reqUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nowUnix := time.Now().Unix()
|
||||||
|
random := rand.Intn(0x989680)
|
||||||
|
|
||||||
|
p4 := fmt.Sprintf("%d|%d|%s|%s|%s|%s", nowUnix, random, reqURL.Path, "web", "3", AuthKeySalt)
|
||||||
|
authKey := fmt.Sprintf("%d-%d-%x", nowUnix, random, md5.Sum([]byte(p4)))
|
||||||
|
return &authKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Pan123) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
func (d *Pan123) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||||
req := base.RestyClient.R()
|
req := base.RestyClient.R()
|
||||||
req.SetHeaders(map[string]string{
|
req.SetHeaders(map[string]string{
|
||||||
@ -86,6 +105,11 @@ func (d *Pan123) request(url string, method string, callback base.ReqCallback, r
|
|||||||
if resp != nil {
|
if resp != nil {
|
||||||
req.SetResult(resp)
|
req.SetResult(resp)
|
||||||
}
|
}
|
||||||
|
authKey, err := authKey(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.SetQueryParam("auth-key", *authKey)
|
||||||
res, err := req.Execute(method, url)
|
res, err := req.Execute(method, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -228,6 +228,8 @@ func (d *AliyundriveOpen) upload(ctx context.Context, dstDir model.Obj, stream m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_ = stream.GetReadCloser().Close()
|
||||||
|
stream.SetReadCloser(file)
|
||||||
// calculate full hash
|
// calculate full hash
|
||||||
h := sha1.New()
|
h := sha1.New()
|
||||||
_, err = io.Copy(h, file)
|
_, err = io.Copy(h, file)
|
||||||
@ -260,7 +262,6 @@ func (d *AliyundriveOpen) upload(ctx context.Context, dstDir model.Obj, stream m
|
|||||||
if _, err = file.Seek(0, io.SeekStart); err != nil {
|
if _, err = file.Seek(0, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stream.SetReadCloser(file)
|
|
||||||
}
|
}
|
||||||
log.Debugf("[aliyundrive_open] create file success, resp: %+v", createResp)
|
log.Debugf("[aliyundrive_open] create file success, resp: %+v", createResp)
|
||||||
return d.normalUpload(ctx, stream, up, createResp, count, partSize)
|
return d.normalUpload(ctx, stream, up, createResp, count, partSize)
|
||||||
|
24
go.mod
24
go.mod
@ -8,7 +8,7 @@ require (
|
|||||||
github.com/Xhofe/wopan-sdk-go v0.1.1
|
github.com/Xhofe/wopan-sdk-go v0.1.1
|
||||||
github.com/avast/retry-go v3.0.0+incompatible
|
github.com/avast/retry-go v3.0.0+incompatible
|
||||||
github.com/aws/aws-sdk-go v1.44.262
|
github.com/aws/aws-sdk-go v1.44.262
|
||||||
github.com/blevesearch/bleve/v2 v2.3.8
|
github.com/blevesearch/bleve/v2 v2.3.9
|
||||||
github.com/caarlos0/env/v9 v9.0.0
|
github.com/caarlos0/env/v9 v9.0.0
|
||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
github.com/deckarep/golang-set/v2 v2.3.0
|
github.com/deckarep/golang-set/v2 v2.3.0
|
||||||
@ -23,14 +23,14 @@ require (
|
|||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0
|
github.com/hirochachacha/go-smb2 v1.1.0
|
||||||
github.com/ipfs/go-ipfs-api v0.6.0
|
github.com/ipfs/go-ipfs-api v0.6.0
|
||||||
github.com/jlaffaye/ftp v0.1.0
|
github.com/jlaffaye/ftp v0.2.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/maruel/natural v1.1.0
|
github.com/maruel/natural v1.1.0
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/sftp v1.13.5
|
github.com/pkg/sftp v1.13.5
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/sirupsen/logrus v1.9.2
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/t3rm1n4l/go-mega v0.0.0-20230228171823-a01a2cda13ca
|
github.com/t3rm1n4l/go-mega v0.0.0-20230228171823-a01a2cda13ca
|
||||||
github.com/u2takey/ffmpeg-go v0.4.1
|
github.com/u2takey/ffmpeg-go v0.4.1
|
||||||
@ -48,7 +48,7 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||||
github.com/RoaringBitmap/roaring v0.9.4 // indirect
|
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
||||||
github.com/aead/ecdh v0.2.0 // indirect
|
github.com/aead/ecdh v0.2.0 // indirect
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible // indirect
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible // indirect
|
||||||
github.com/andreburgaud/crypt2go v1.1.0 // indirect
|
github.com/andreburgaud/crypt2go v1.1.0 // indirect
|
||||||
@ -59,16 +59,16 @@ require (
|
|||||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4 // indirect
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 // indirect
|
||||||
github.com/blevesearch/segment v0.9.1 // indirect
|
github.com/blevesearch/segment v0.9.1 // indirect
|
||||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||||
github.com/blevesearch/vellum v1.0.9 // indirect
|
github.com/blevesearch/vellum v1.0.10 // indirect
|
||||||
github.com/blevesearch/zapx/v11 v11.3.7 // indirect
|
github.com/blevesearch/zapx/v11 v11.3.9 // indirect
|
||||||
github.com/blevesearch/zapx/v12 v12.3.7 // indirect
|
github.com/blevesearch/zapx/v12 v12.3.9 // indirect
|
||||||
github.com/blevesearch/zapx/v13 v13.3.7 // indirect
|
github.com/blevesearch/zapx/v13 v13.3.9 // indirect
|
||||||
github.com/blevesearch/zapx/v14 v14.3.7 // indirect
|
github.com/blevesearch/zapx/v14 v14.3.9 // indirect
|
||||||
github.com/blevesearch/zapx/v15 v15.3.10 // indirect
|
github.com/blevesearch/zapx/v15 v15.3.12 // indirect
|
||||||
github.com/bluele/gcache v0.0.2 // indirect
|
github.com/bluele/gcache v0.0.2 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
@ -131,7 +131,7 @@ require (
|
|||||||
github.com/u2takey/go-utils v0.3.1 // indirect
|
github.com/u2takey/go-utils v0.3.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c // indirect
|
github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c // indirect
|
||||||
go.etcd.io/bbolt v1.3.5 // indirect
|
go.etcd.io/bbolt v1.3.7 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.11.0 // indirect
|
||||||
|
49
go.sum
49
go.sum
@ -1,7 +1,7 @@
|
|||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/RoaringBitmap/roaring v0.9.4 h1:ckvZSX5gwCRaJYBNe7syNawCU5oruY9gQmjXlp4riwo=
|
github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY=
|
||||||
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
|
github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
|
||||||
github.com/SheltonZhu/115driver v1.0.14 h1:uW3dl8J9KDMw+3gPxQdhTysoGhw0/uI1484GT9xhfU4=
|
github.com/SheltonZhu/115driver v1.0.14 h1:uW3dl8J9KDMw+3gPxQdhTysoGhw0/uI1484GT9xhfU4=
|
||||||
github.com/SheltonZhu/115driver v1.0.14/go.mod h1:00ixivHH5HqDj4S7kAWbkuUrjtsJTxc7cGv5RMw3RVs=
|
github.com/SheltonZhu/115driver v1.0.14/go.mod h1:00ixivHH5HqDj4S7kAWbkuUrjtsJTxc7cGv5RMw3RVs=
|
||||||
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a h1:RenIAa2q4H8UcS/cqmwdT1WCWIAH5aumP8m8RpbqVsE=
|
github.com/Xhofe/go-cache v0.0.0-20220723083548-714439c8af9a h1:RenIAa2q4H8UcS/cqmwdT1WCWIAH5aumP8m8RpbqVsE=
|
||||||
@ -23,8 +23,8 @@ github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT
|
|||||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||||
github.com/blevesearch/bleve/v2 v2.3.8 h1:IqFyMJ73n4gY8AmVqM8Sa6EtAZ5beE8yramVqCvs2kQ=
|
github.com/blevesearch/bleve/v2 v2.3.9 h1:pUMvK0mxAexqasZcVj8lazmWnEW5XiV0tASIqANiNTQ=
|
||||||
github.com/blevesearch/bleve/v2 v2.3.8/go.mod h1:Lh9aZEHrLKxwPnW4z4lsBEGnflZQ1V/aWP/t+htsiDw=
|
github.com/blevesearch/bleve/v2 v2.3.9/go.mod h1:1PibElcjlQMQHF9uS9mRv58ODQgj4pCWHA1Wfd+qagU=
|
||||||
github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
||||||
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||||
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
||||||
@ -35,26 +35,26 @@ github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZG
|
|||||||
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
||||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4 h1:LmGmo5twU3gV+natJbKmOktS9eMhokPGKWuR+jX84vk=
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.5 h1:1g713kpCQZ8u4a3stRGBfrwVOuGRnmxOVU5MQkUPrHU=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4/go.mod h1:PgVnbbg/t1UkgezPDu8EHLi1BHQ17xUwsFdU6NnOYS0=
|
github.com/blevesearch/scorch_segment_api/v2 v2.1.5/go.mod h1:f2nOkKS1HcjgIWZgDAErgBdxmr2eyt0Kn7IY+FU1Xe4=
|
||||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||||
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||||
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
|
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
|
||||||
github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A=
|
github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A=
|
||||||
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
|
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
|
||||||
github.com/blevesearch/vellum v1.0.9 h1:PL+NWVk3dDGPCV0hoDu9XLLJgqU4E5s/dOeEJByQ2uQ=
|
github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI=
|
||||||
github.com/blevesearch/vellum v1.0.9/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
||||||
github.com/blevesearch/zapx/v11 v11.3.7 h1:Y6yIAF/DVPiqZUA/jNgSLXmqewfzwHzuwfKyfdG+Xaw=
|
github.com/blevesearch/zapx/v11 v11.3.9 h1:y3ijS4h4MJdmQ07MHASxat4owAixreK2xdo76w9ncrw=
|
||||||
github.com/blevesearch/zapx/v11 v11.3.7/go.mod h1:Xk9Z69AoAWIOvWudNDMlxJDqSYGf90LS0EfnaAIvXCA=
|
github.com/blevesearch/zapx/v11 v11.3.9/go.mod h1:jcAYnQwlr+LqD2vLjDWjWiZDXDXGFqPbpPDRTd3XmS4=
|
||||||
github.com/blevesearch/zapx/v12 v12.3.7 h1:DfQ6rsmZfEK4PzzJJRXjiM6AObG02+HWvprlXQ1Y7eI=
|
github.com/blevesearch/zapx/v12 v12.3.9 h1:MXGLlZ03oxXH3DMJTZaBaRj2xb6t4wQVZeZK/wu1M6w=
|
||||||
github.com/blevesearch/zapx/v12 v12.3.7/go.mod h1:SgEtYIBGvM0mgIBn2/tQE/5SdrPXaJUaT/kVqpAPxm0=
|
github.com/blevesearch/zapx/v12 v12.3.9/go.mod h1:QXCMwmOkdLnMDgTN1P4CcuX5F851iUOtOwXbw0HMBYs=
|
||||||
github.com/blevesearch/zapx/v13 v13.3.7 h1:igIQg5eKmjw168I7av0Vtwedf7kHnQro/M+ubM4d2l8=
|
github.com/blevesearch/zapx/v13 v13.3.9 h1:+VAz9V0VmllHXlZV4DCvfYj0nqaZHgF3MeEHwOyRBwQ=
|
||||||
github.com/blevesearch/zapx/v13 v13.3.7/go.mod h1:yyrB4kJ0OT75UPZwT/zS+Ru0/jYKorCOOSY5dBzAy+s=
|
github.com/blevesearch/zapx/v13 v13.3.9/go.mod h1:s+WjNp4WSDtrBVBpa37DUOd7S/Gr/jTZ7ST/MbCVj/0=
|
||||||
github.com/blevesearch/zapx/v14 v14.3.7 h1:gfe+fbWslDWP/evHLtp/GOvmNM3sw1BbqD7LhycBX20=
|
github.com/blevesearch/zapx/v14 v14.3.9 h1:wuqxATgsTCNHM9xsOFOeFp8H2heZ/gMX/tsl9lRK8U4=
|
||||||
github.com/blevesearch/zapx/v14 v14.3.7/go.mod h1:9J/RbOkqZ1KSjmkOes03AkETX7hrXT0sFMpWH4ewC4w=
|
github.com/blevesearch/zapx/v14 v14.3.9/go.mod h1:MWZ4v8AzFBRurhDzkLvokFW8ljcq9Evm27mkWe8OGbM=
|
||||||
github.com/blevesearch/zapx/v15 v15.3.10 h1:bQ9ZxJCj6rKp873EuVJu2JPxQ+EWQZI1cjJGeroovaQ=
|
github.com/blevesearch/zapx/v15 v15.3.12 h1:w/kU9aHyfMDEdwHGZzCiakC3HZ9z5gYlXaALDC4Dct8=
|
||||||
github.com/blevesearch/zapx/v15 v15.3.10/go.mod h1:m7Y6m8soYUvS7MjN9eKlz1xrLCcmqfFadmu7GhWIrLY=
|
github.com/blevesearch/zapx/v15 v15.3.12/go.mod h1:tx53gDJS/7Oa3Je820cmVurqCuJ4dqdAy1kiDMV/IUo=
|
||||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
@ -169,8 +169,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
|||||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jlaffaye/ftp v0.1.0 h1:DLGExl5nBoSFoNshAUHwXAezXwXBvFdx7/qwhucWNSE=
|
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
|
||||||
github.com/jlaffaye/ftp v0.1.0/go.mod h1:hhq4G4crv+nW2qXtNYcuzLeOudG92Ps37HEKeg2e3lE=
|
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
@ -268,8 +268,8 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
|
|||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
@ -315,8 +315,8 @@ github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:
|
|||||||
github.com/winfsp/cgofuse v1.5.0 h1:MsBP7Mi/LiJf/7/F3O/7HjjR009ds6KCdqXzKpZSWxI=
|
github.com/winfsp/cgofuse v1.5.0 h1:MsBP7Mi/LiJf/7/F3O/7HjjR009ds6KCdqXzKpZSWxI=
|
||||||
github.com/winfsp/cgofuse v1.5.0/go.mod h1:h3awhoUOcn2VYVKCwDaYxSLlZwnyK+A8KaDoLUp2lbU=
|
github.com/winfsp/cgofuse v1.5.0/go.mod h1:h3awhoUOcn2VYVKCwDaYxSLlZwnyK+A8KaDoLUp2lbU=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
@ -358,7 +358,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -154,13 +154,16 @@ func InitialSettings() []model.SettingItem {
|
|||||||
|
|
||||||
// SSO settings
|
// SSO settings
|
||||||
{Key: conf.SSOLoginEnabled, Value: "false", Type: conf.TypeBool, Group: model.SSO, Flag: model.PUBLIC},
|
{Key: conf.SSOLoginEnabled, Value: "false", Type: conf.TypeBool, Group: model.SSO, Flag: model.PUBLIC},
|
||||||
{Key: conf.SSOLoginplatform, Type: conf.TypeSelect, Options: "Casdoor,Github,Microsoft,Google,Dingtalk,OIDC", Group: model.SSO, Flag: model.PUBLIC},
|
{Key: conf.SSOLoginPlatform, Type: conf.TypeSelect, Options: "Casdoor,Github,Microsoft,Google,Dingtalk,OIDC", Group: model.SSO, Flag: model.PUBLIC},
|
||||||
{Key: conf.SSOClientId, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOClientId, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
{Key: conf.SSOClientSecret, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOClientSecret, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
{Key: conf.SSOOrganizationName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOOrganizationName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
{Key: conf.SSOApplicationName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOApplicationName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
{Key: conf.SSOEndpointName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOEndpointName, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
{Key: conf.SSOJwtPublicKey, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
{Key: conf.SSOJwtPublicKey, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
|
{Key: conf.SSOAutoRegister, Value: "false", Type: conf.TypeBool, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
|
{Key: conf.SSODefaultDir, Value: "/", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
|
{Key: conf.SSODefaultPermission, Value: "0", Type: conf.TypeNumber, Group: model.SSO, Flag: model.PRIVATE},
|
||||||
|
|
||||||
// qbittorrent settings
|
// qbittorrent settings
|
||||||
{Key: conf.QbittorrentUrl, Value: "http://admin:adminadmin@localhost:8080/", Type: conf.TypeString, Group: model.SINGLE, Flag: model.PRIVATE},
|
{Key: conf.QbittorrentUrl, Value: "http://admin:adminadmin@localhost:8080/", Type: conf.TypeString, Group: model.SINGLE, Flag: model.PRIVATE},
|
||||||
|
@ -57,14 +57,17 @@ const (
|
|||||||
IndexProgress = "index_progress"
|
IndexProgress = "index_progress"
|
||||||
|
|
||||||
//SSO
|
//SSO
|
||||||
SSOClientId = "sso_client_id"
|
SSOClientId = "sso_client_id"
|
||||||
SSOClientSecret = "sso_client_secret"
|
SSOClientSecret = "sso_client_secret"
|
||||||
SSOLoginEnabled = "sso_login_enabled"
|
SSOLoginEnabled = "sso_login_enabled"
|
||||||
SSOLoginplatform = "sso_login_platform"
|
SSOLoginPlatform = "sso_login_platform"
|
||||||
SSOOrganizationName = "sso_organization_name"
|
SSOOrganizationName = "sso_organization_name"
|
||||||
SSOApplicationName = "sso_application_name"
|
SSOApplicationName = "sso_application_name"
|
||||||
SSOEndpointName = "sso_endpoint_name"
|
SSOEndpointName = "sso_endpoint_name"
|
||||||
SSOJwtPublicKey = "sso_jwt_public_key"
|
SSOJwtPublicKey = "sso_jwt_public_key"
|
||||||
|
SSOAutoRegister = "sso_auto_register"
|
||||||
|
SSODefaultDir = "sso_default_dir"
|
||||||
|
SSODefaultPermission = "sso_default_permission"
|
||||||
|
|
||||||
// qbittorrent
|
// qbittorrent
|
||||||
QbittorrentUrl = "qbittorrent_url"
|
QbittorrentUrl = "qbittorrent_url"
|
||||||
|
@ -33,7 +33,7 @@ type User struct {
|
|||||||
// 10: can add qbittorrent tasks
|
// 10: can add qbittorrent tasks
|
||||||
Permission int32 `json:"permission"`
|
Permission int32 `json:"permission"`
|
||||||
OtpSecret string `json:"-"`
|
OtpSecret string `json:"-"`
|
||||||
SsoID string `json:"sso_id"`
|
SsoID string `json:"sso_id"` // unique by sso platform
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) IsGuest() bool {
|
func (u User) IsGuest() bool {
|
||||||
|
@ -11,8 +11,10 @@ import (
|
|||||||
|
|
||||||
"github.com/alist-org/alist/v3/internal/conf"
|
"github.com/alist-org/alist/v3/internal/conf"
|
||||||
"github.com/alist-org/alist/v3/internal/db"
|
"github.com/alist-org/alist/v3/internal/db"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
"github.com/alist-org/alist/v3/internal/setting"
|
"github.com/alist-org/alist/v3/internal/setting"
|
||||||
"github.com/alist-org/alist/v3/pkg/utils"
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils/random"
|
||||||
"github.com/alist-org/alist/v3/server/common"
|
"github.com/alist-org/alist/v3/server/common"
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -20,14 +22,15 @@ import (
|
|||||||
"github.com/pquerna/otp"
|
"github.com/pquerna/otp"
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var opts = totp.ValidateOpts{
|
var opts = totp.ValidateOpts{
|
||||||
// state verify won't expire in 30 secs, which is quite enough for the callback
|
// state verify won't expire in 30 secs, which is quite enough for the callback
|
||||||
Period: 30,
|
Period: 30,
|
||||||
Skew: 1,
|
Skew: 1,
|
||||||
// in some OIDC providers(such as Authelia), state parameter must be at least 8 characters
|
// in some OIDC providers(such as Authelia), state parameter must be at least 8 characters
|
||||||
Digits: otp.DigitsEight,
|
Digits: otp.DigitsEight,
|
||||||
Algorithm: otp.AlgorithmSHA1,
|
Algorithm: otp.AlgorithmSHA1,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +38,7 @@ func SSOLoginRedirect(c *gin.Context) {
|
|||||||
method := c.Query("method")
|
method := c.Query("method")
|
||||||
enabled := setting.GetBool(conf.SSOLoginEnabled)
|
enabled := setting.GetBool(conf.SSOLoginEnabled)
|
||||||
clientId := setting.GetStr(conf.SSOClientId)
|
clientId := setting.GetStr(conf.SSOClientId)
|
||||||
platform := setting.GetStr(conf.SSOLoginplatform)
|
platform := setting.GetStr(conf.SSOLoginPlatform)
|
||||||
var r_url string
|
var r_url string
|
||||||
var redirect_uri string
|
var redirect_uri string
|
||||||
if enabled {
|
if enabled {
|
||||||
@ -76,7 +79,7 @@ func SSOLoginRedirect(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// generate state parameter
|
// generate state parameter
|
||||||
state,err := totp.GenerateCodeCustom(base32.StdEncoding.EncodeToString([]byte(oauth2Config.ClientSecret)), time.Now(), opts)
|
state, err := totp.GenerateCodeCustom(base32.StdEncoding.EncodeToString([]byte(oauth2Config.ClientSecret)), time.Now(), opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorStrResp(c, err.Error(), 400)
|
common.ErrorStrResp(c, err.Error(), 400)
|
||||||
return
|
return
|
||||||
@ -118,13 +121,39 @@ func GetOIDCClient(c *gin.Context) (*oauth2.Config, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoRegister(username, userID string, err error) (*model.User, error) {
|
||||||
|
if !errors.Is(err, gorm.ErrRecordNotFound) || !setting.GetBool(conf.SSOAutoRegister) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if username == "" {
|
||||||
|
return nil, errors.New("cannot get username from SSO provider")
|
||||||
|
}
|
||||||
|
user := &model.User{
|
||||||
|
ID: 0,
|
||||||
|
Username: username,
|
||||||
|
Password: random.String(16),
|
||||||
|
Permission: int32(setting.GetInt(conf.SSODefaultPermission, 0)),
|
||||||
|
BasePath: setting.GetStr(conf.SSODefaultDir),
|
||||||
|
Role: 0,
|
||||||
|
Disabled: false,
|
||||||
|
SsoID: userID,
|
||||||
|
}
|
||||||
|
if err = db.CreateUser(user); err != nil {
|
||||||
|
if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") && strings.HasSuffix(err.Error(), "username") {
|
||||||
|
user.Username = user.Username + "_" + userID
|
||||||
|
if err = db.CreateUser(user); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
func OIDCLoginCallback(c *gin.Context) {
|
func OIDCLoginCallback(c *gin.Context) {
|
||||||
argument := c.Query("method")
|
argument := c.Query("method")
|
||||||
enabled := setting.GetBool(conf.SSOLoginEnabled)
|
|
||||||
clientId := setting.GetStr(conf.SSOClientId)
|
clientId := setting.GetStr(conf.SSOClientId)
|
||||||
if !enabled {
|
|
||||||
common.ErrorResp(c, errors.New("invalid request"), 500)
|
|
||||||
}
|
|
||||||
endpoint := setting.GetStr(conf.SSOEndpointName)
|
endpoint := setting.GetStr(conf.SSOEndpointName)
|
||||||
provider, err := oidc.NewProvider(c, endpoint)
|
provider, err := oidc.NewProvider(c, endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -170,7 +199,7 @@ func OIDCLoginCallback(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
claims := UserInfo{}
|
claims := UserInfo{}
|
||||||
if err := idToken.Claims(&claims); err != nil {
|
if err := idToken.Claims(&claims); err != nil {
|
||||||
c.Error(err)
|
common.ErrorResp(c, err, 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
UserID := claims.Name
|
UserID := claims.Name
|
||||||
@ -189,7 +218,10 @@ func OIDCLoginCallback(c *gin.Context) {
|
|||||||
if argument == "sso_get_token" {
|
if argument == "sso_get_token" {
|
||||||
user, err := db.GetUserBySSOID(UserID)
|
user, err := db.GetUserBySSOID(UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 400)
|
user, err = autoRegister(UserID, UserID, err)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
token, err := common.GenerateToken(user.Username)
|
token, err := common.GenerateToken(user.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -209,133 +241,145 @@ func OIDCLoginCallback(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SSOLoginCallback(c *gin.Context) {
|
func SSOLoginCallback(c *gin.Context) {
|
||||||
|
enabled := setting.GetBool(conf.SSOLoginEnabled)
|
||||||
|
if !enabled {
|
||||||
|
common.ErrorResp(c, errors.New("sso login is disabled"), 500)
|
||||||
|
}
|
||||||
argument := c.Query("method")
|
argument := c.Query("method")
|
||||||
if argument == "get_sso_id" || argument == "sso_get_token" {
|
if !utils.SliceContains([]string{"get_sso_id", "sso_get_token"}, argument) {
|
||||||
enabled := setting.GetBool(conf.SSOLoginEnabled)
|
common.ErrorResp(c, errors.New("invalid request"), 500)
|
||||||
clientId := setting.GetStr(conf.SSOClientId)
|
}
|
||||||
platform := setting.GetStr(conf.SSOLoginplatform)
|
clientId := setting.GetStr(conf.SSOClientId)
|
||||||
clientSecret := setting.GetStr(conf.SSOClientSecret)
|
platform := setting.GetStr(conf.SSOLoginPlatform)
|
||||||
var url1, url2, additionalbody, scope, authstring, idstring string
|
clientSecret := setting.GetStr(conf.SSOClientSecret)
|
||||||
switch platform {
|
var tokenUrl, userUrl, scope, authField, idField, usernameField string
|
||||||
case "Github":
|
additionalForm := make(map[string]string)
|
||||||
url1 = "https://github.com/login/oauth/access_token"
|
switch platform {
|
||||||
url2 = "https://api.github.com/user"
|
case "Github":
|
||||||
additionalbody = ""
|
tokenUrl = "https://github.com/login/oauth/access_token"
|
||||||
authstring = "code"
|
userUrl = "https://api.github.com/user"
|
||||||
scope = "read:user"
|
authField = "code"
|
||||||
idstring = "id"
|
scope = "read:user"
|
||||||
case "Microsoft":
|
idField = "id"
|
||||||
url1 = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
|
usernameField = "login"
|
||||||
url2 = "https://graph.microsoft.com/v1.0/me"
|
case "Microsoft":
|
||||||
additionalbody = "&grant_type=authorization_code"
|
tokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
|
||||||
scope = "user.read"
|
userUrl = "https://graph.microsoft.com/v1.0/me"
|
||||||
authstring = "code"
|
additionalForm["grant_type"] = "authorization_code"
|
||||||
idstring = "id"
|
scope = "user.read"
|
||||||
case "Google":
|
authField = "code"
|
||||||
url1 = "https://oauth2.googleapis.com/token"
|
idField = "id"
|
||||||
url2 = "https://www.googleapis.com/oauth2/v1/userinfo"
|
usernameField = "displayName"
|
||||||
additionalbody = "&grant_type=authorization_code"
|
case "Google":
|
||||||
scope = "https://www.googleapis.com/auth/userinfo.profile"
|
tokenUrl = "https://oauth2.googleapis.com/token"
|
||||||
authstring = "code"
|
userUrl = "https://www.googleapis.com/oauth2/v1/userinfo"
|
||||||
idstring = "id"
|
additionalForm["grant_type"] = "authorization_code"
|
||||||
case "Dingtalk":
|
scope = "https://www.googleapis.com/auth/userinfo.profile"
|
||||||
url1 = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken"
|
authField = "code"
|
||||||
url2 = "https://api.dingtalk.com/v1.0/contact/users/me"
|
idField = "id"
|
||||||
authstring = "authCode"
|
usernameField = "name"
|
||||||
idstring = "unionId"
|
case "Dingtalk":
|
||||||
case "Casdoor":
|
tokenUrl = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken"
|
||||||
endpoint := strings.TrimSuffix(setting.GetStr(conf.SSOEndpointName), "/")
|
userUrl = "https://api.dingtalk.com/v1.0/contact/users/me"
|
||||||
url1 = endpoint + "/api/login/oauth/access_token"
|
authField = "authCode"
|
||||||
url2 = endpoint + "/api/userinfo"
|
idField = "unionId"
|
||||||
additionalbody = "&grant_type=authorization_code"
|
usernameField = "nick"
|
||||||
scope = "profile"
|
case "Casdoor":
|
||||||
authstring = "code"
|
endpoint := strings.TrimSuffix(setting.GetStr(conf.SSOEndpointName), "/")
|
||||||
idstring = "preferred_username"
|
tokenUrl = endpoint + "/api/login/oauth/access_token"
|
||||||
case "OIDC":
|
userUrl = endpoint + "/api/userinfo"
|
||||||
OIDCLoginCallback(c)
|
additionalForm["grant_type"] = "authorization_code"
|
||||||
return
|
scope = "profile"
|
||||||
default:
|
authField = "code"
|
||||||
common.ErrorStrResp(c, "invalid platform", 400)
|
idField = "sub"
|
||||||
return
|
usernameField = "preferred_username"
|
||||||
}
|
case "OIDC":
|
||||||
if enabled {
|
OIDCLoginCallback(c)
|
||||||
callbackCode := c.Query(authstring)
|
return
|
||||||
if callbackCode == "" {
|
default:
|
||||||
common.ErrorStrResp(c, "No code provided", 400)
|
common.ErrorStrResp(c, "invalid platform", 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var resp *resty.Response
|
callbackCode := c.Query(authField)
|
||||||
var err error
|
if callbackCode == "" {
|
||||||
if platform == "Dingtalk" {
|
common.ErrorStrResp(c, "No code provided", 400)
|
||||||
resp, err = ssoClient.R().SetHeader("content-type", "application/json").SetHeader("Accept", "application/json").
|
return
|
||||||
SetBody(map[string]string{
|
}
|
||||||
"clientId": clientId,
|
var resp *resty.Response
|
||||||
"clientSecret": clientSecret,
|
var err error
|
||||||
"code": callbackCode,
|
if platform == "Dingtalk" {
|
||||||
"grantType": "authorization_code",
|
resp, err = ssoClient.R().SetHeader("content-type", "application/json").SetHeader("Accept", "application/json").
|
||||||
}).
|
SetBody(map[string]string{
|
||||||
Post(url1)
|
"clientId": clientId,
|
||||||
} else {
|
"clientSecret": clientSecret,
|
||||||
resp, err = ssoClient.R().SetHeader("content-type", "application/x-www-form-urlencoded").SetHeader("Accept", "application/json").
|
"code": callbackCode,
|
||||||
SetBody("client_id=" + clientId + "&client_secret=" + clientSecret + "&code=" + callbackCode + "&redirect_uri=" + common.GetApiUrl(c.Request) + "/api/auth/sso_callback?method=" + argument + "&scope=" + scope + additionalbody).
|
"grantType": "authorization_code",
|
||||||
Post(url1)
|
}).
|
||||||
}
|
Post(tokenUrl)
|
||||||
if err != nil {
|
} else {
|
||||||
common.ErrorResp(c, err, 400)
|
resp, err = ssoClient.R().SetHeader("Accept", "application/json").
|
||||||
return
|
SetFormData(map[string]string{
|
||||||
}
|
"client_id": clientId,
|
||||||
if platform == "Dingtalk" {
|
"client_secret": clientSecret,
|
||||||
accessToken := utils.Json.Get(resp.Body(), "accessToken").ToString()
|
"code": callbackCode,
|
||||||
resp, err = ssoClient.R().SetHeader("x-acs-dingtalk-access-token", accessToken).
|
"redirect_uri": common.GetApiUrl(c.Request) + "/api/auth/sso_callback?method=" + argument,
|
||||||
Get(url2)
|
"scope": scope,
|
||||||
} else {
|
}).SetFormData(additionalForm).Post(tokenUrl)
|
||||||
accessToken := utils.Json.Get(resp.Body(), "access_token").ToString()
|
}
|
||||||
resp, err = ssoClient.R().SetHeader("Authorization", "Bearer "+accessToken).
|
if err != nil {
|
||||||
Get(url2)
|
common.ErrorResp(c, err, 400)
|
||||||
}
|
return
|
||||||
if err != nil {
|
}
|
||||||
common.ErrorResp(c, err, 400)
|
if platform == "Dingtalk" {
|
||||||
return
|
accessToken := utils.Json.Get(resp.Body(), "accessToken").ToString()
|
||||||
}
|
resp, err = ssoClient.R().SetHeader("x-acs-dingtalk-access-token", accessToken).
|
||||||
UserID := utils.Json.Get(resp.Body(), idstring).ToString()
|
Get(userUrl)
|
||||||
if UserID == "0" {
|
} else {
|
||||||
common.ErrorResp(c, errors.New("error occured"), 400)
|
accessToken := utils.Json.Get(resp.Body(), "access_token").ToString()
|
||||||
return
|
resp, err = ssoClient.R().SetHeader("Authorization", "Bearer "+accessToken).
|
||||||
}
|
Get(userUrl)
|
||||||
if argument == "get_sso_id" {
|
}
|
||||||
html := fmt.Sprintf(`<!DOCTYPE html>
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userID := utils.Json.Get(resp.Body(), idField).ToString()
|
||||||
|
if utils.SliceContains([]string{"", "0"}, userID) {
|
||||||
|
common.ErrorResp(c, errors.New("error occured"), 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if argument == "get_sso_id" {
|
||||||
|
html := fmt.Sprintf(`<!DOCTYPE html>
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
window.opener.postMessage({"sso_id": "%s"}, "*")
|
window.opener.postMessage({"sso_id": "%s"}, "*")
|
||||||
window.close()
|
window.close()
|
||||||
</script>
|
</script>
|
||||||
</body>`, UserID)
|
</body>`, userID)
|
||||||
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if argument == "sso_get_token" {
|
username := utils.Json.Get(resp.Body(), usernameField).ToString()
|
||||||
user, err := db.GetUserBySSOID(UserID)
|
user, err := db.GetUserBySSOID(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 400)
|
user, err = autoRegister(username, userID, err)
|
||||||
}
|
if err != nil {
|
||||||
token, err := common.GenerateToken(user.Username)
|
common.ErrorResp(c, err, 400)
|
||||||
if err != nil {
|
return
|
||||||
common.ErrorResp(c, err, 400)
|
|
||||||
}
|
|
||||||
html := fmt.Sprintf(`<!DOCTYPE html>
|
|
||||||
<head></head>
|
|
||||||
<body>
|
|
||||||
<script>
|
|
||||||
window.opener.postMessage({"token":"%s"}, "*")
|
|
||||||
window.close()
|
|
||||||
</script>
|
|
||||||
</body>`, token)
|
|
||||||
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
common.ErrorResp(c, errors.New("invalid request"), 500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
token, err := common.GenerateToken(user.Username)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
}
|
||||||
|
html := fmt.Sprintf(`<!DOCTYPE html>
|
||||||
|
<head></head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.opener.postMessage({"token":"%s"}, "*")
|
||||||
|
window.close()
|
||||||
|
</script>
|
||||||
|
</body>`, token)
|
||||||
|
c.Data(200, "text/html; charset=utf-8", []byte(html))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user