Compare commits

..

9 Commits

Author SHA1 Message Date
Noah Hsu bd52df1926 ci: use own proxy musl url 2022-08-14 15:38:22 +08:00
Noah Hsu ba9d568539 fix: add -password flag back 2022-08-13 20:56:19 +08:00
Noah Hsu a66b2d92b7 ci: use personal token 2022-08-13 11:52:14 +08:00
Noah Hsu 0b3c5f3e2b fix: random password of webdav guest user 2022-08-13 11:28:40 +08:00
kbtxwer cc74effd30 feat: add chaoxing support (#1457)
Co-authored-by: Admin <kbtxwer@qq.com>
2022-08-13 11:25:50 +08:00
wenxuan70 51b8b4380d feat: integrate alist with casdoor (#1453)
* feat: integrate alist with casdoor

* fix: casdoor as an option for login

Co-authored-by: wenxuan70 <t736660416@gmail.com>
2022-08-06 16:47:39 +08:00
Noah Hsu 5e59b0a697 docs: fix typo [skip ci] 2022-07-28 18:53:05 +08:00
Noah Hsu 1d3b86985f fix: config json and env tag 2022-07-22 13:40:12 +08:00
Noah Hsu c711ba53a3 fix!: change default assets to local 2022-07-22 13:39:25 +08:00
23 changed files with 1013 additions and 41 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
fetch-depth: 0
- run: npx changelogithub # or changelogithub@0.12 if ensure the stable result
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
GITHUB_TOKEN: ${{secrets.MY_TOKEN}}
release:
needs: changelog
strategy:
+1 -1
View File
@@ -73,7 +73,7 @@ Available at: <https://alist.nn.ci>.
## Special sponsors
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
- [KinhDown 百度云盘不限速下载!永久免费!以稳定运行3年!非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [KinhDown 百度云盘不限速下载!永久免费!已稳定运行3年!非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
## License
+1 -1
View File
@@ -73,7 +73,7 @@
## 特别赞助
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
- [KinhDown 百度云盘不限速下载!永久免费!以稳定运行3年!非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [KinhDown 百度云盘不限速下载!永久免费!已稳定运行3年!非常可靠!](https://kinhdown.com/?Type=Tutorials)
- [JetBrains: Essential tools for software developers and teams](https://www.jetbrains.com/)
## 许可
+2
View File
@@ -2,6 +2,7 @@ package main
import (
"fmt"
"github.com/Xhofe/alist/bootstrap"
"github.com/Xhofe/alist/conf"
_ "github.com/Xhofe/alist/drivers"
@@ -26,6 +27,7 @@ func Init() bool {
}
server.InitIndex()
bootstrap.InitSettings()
bootstrap.InitAuth()
bootstrap.InitAccounts()
bootstrap.InitCache()
return true
+51
View File
@@ -0,0 +1,51 @@
package bootstrap
import (
"github.com/Xhofe/alist/conf"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
log "github.com/sirupsen/logrus"
"strings"
)
type AuthConfig struct {
OrganizationName string `json:"organization_name"`
ApplicationName string `json:"application_name"`
Endpoint string `json:"endpoint"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
JwtPublicKey string `json:"jwt_public_key"`
}
// InitAuth init auth
func InitAuth() {
log.Infof("init auth...")
enableCasdoor := conf.GetBool("Enable Casdoor")
if !enableCasdoor {
return
}
auth := readAuthConfig()
if !CheckAuthConfig(auth) {
panic("invalid auth config")
}
casdoorsdk.InitConfig(strings.TrimRight(auth.Endpoint, "/"), auth.ClientId, auth.ClientSecret, auth.JwtPublicKey, auth.OrganizationName, auth.ApplicationName)
}
func readAuthConfig() AuthConfig {
return AuthConfig{
OrganizationName: conf.GetStr("Casdoor Organization name"),
ApplicationName: conf.GetStr("Casdoor Application name"),
Endpoint: conf.GetStr("Casdoor Endpoint"),
ClientId: conf.GetStr("Casdoor Client id"),
ClientSecret: conf.GetStr("Casdoor Client secret"),
JwtPublicKey: conf.GetStr("Casdoor Jwt Public Key"),
}
}
func CheckAuthConfig(authConfig AuthConfig) bool {
return authConfig.Endpoint != "" &&
authConfig.ClientId != "" &&
authConfig.ClientSecret != "" &&
authConfig.OrganizationName != "" &&
authConfig.ApplicationName != "" &&
authConfig.JwtPublicKey != ""
}
+1
View File
@@ -2,6 +2,7 @@ package bootstrap
import (
"flag"
"github.com/Xhofe/alist/conf"
log "github.com/sirupsen/logrus"
)
+59 -2
View File
@@ -1,12 +1,13 @@
package bootstrap
import (
"strings"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
"strings"
)
func InitSettings() {
@@ -235,7 +236,7 @@ func InitSettings() {
},
{
Key: "Visitor WebDAV password",
Value: "guest",
Value: utils.RandomStr(8),
Description: "Visitor WebDAV password",
Type: "string",
Access: model.PRIVATE,
@@ -289,6 +290,62 @@ func InitSettings() {
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Enable Casdoor",
Value: "false",
Description: "Enable Casdoor login",
Type: "bool",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Organization name",
Value: "",
Description: "Casdoor Organization name",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Application name",
Value: "",
Description: "Casdoor Application name",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Endpoint",
Value: "",
Description: "Casdoor Endpoint, e.g. 'http://localhost:8000'",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Client id",
Value: "",
Description: "Casdoor Client id",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Client secret",
Value: "",
Description: "Casdoor Client secret",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
{
Key: "Casdoor Jwt Public Key",
Value: "",
Description: "Casdoor Jwt Public Key",
Type: "string",
Access: model.PRIVATE,
Group: model.BACK,
},
}
for i, _ := range settings {
v := settings[i]
+1 -1
View File
@@ -81,7 +81,7 @@ BUILD() {
}
BUILD_MUSL() {
BASE="https://musl.cc/"
BASE="https://musl.nn.ci/"
FILES=(x86_64-linux-musl-cross aarch64-linux-musl-cross arm-linux-musleabihf-cross mips-linux-musl-cross mips64-linux-musl-cross mips64el-linux-musl-cross mipsel-linux-musl-cross powerpc64le-linux-musl-cross s390x-linux-musl-cross)
for i in "${FILES[@]}"; do
url="${BASE}${i}.tgz"
+15 -15
View File
@@ -24,26 +24,26 @@ type CacheConfig struct {
}
type Config struct {
Force bool `json:"force"`
Address string `json:"address" env:"ADDR"`
Port int `json:"port" env:"PORT"`
Assets string `json:"assets" env:"ASSETS"`
LocalAssets string `json:"localassets" env:"LOCALASSETS"`
SubFolder string `json:"subfolder" env:"SUBFOLDER"`
Database Database `json:"database"`
Scheme Scheme `json:"scheme"`
Cache CacheConfig `json:"cache"`
TempDir string `json:"temp_dir" env:"TEMP_DIR"`
Force bool `json:"force"`
Address string `json:"address" env:"ADDR"`
Port int `json:"port" env:"PORT"`
Assets string `json:"assets" env:"ASSETS"`
LocalAssets string `json:"local_assets" env:"LOCAL_ASSETS"`
SubFolder string `json:"sub_folder" env:"SUB_FOLDER"`
Database Database `json:"database"`
Scheme Scheme `json:"scheme"`
Cache CacheConfig `json:"cache"`
TempDir string `json:"temp_dir" env:"TEMP_DIR"`
}
func DefaultConfig() *Config {
return &Config{
Address: "0.0.0.0",
Port: 5244,
Assets: "https://npm.elemecdn.com/alist-web@$version/dist",
SubFolder: "",
Address: "0.0.0.0",
Port: 5244,
Assets: "/",
SubFolder: "",
LocalAssets: "",
TempDir: "data/temp",
TempDir: "data/temp",
Database: Database{
Type: "sqlite3",
Port: 0,
+3
View File
@@ -86,6 +86,9 @@ var (
"default page size", "load type",
"ocr api", "favicon",
"enable search",
"Enable Casdoor", "Casdoor Organization name", "Casdoor Application name",
"Casdoor Endpoint", "Casdoor Client id", "Casdoor Client secret",
"Casdoor Jwt Public Key",
}
)
+1 -1
View File
@@ -29,7 +29,7 @@ func (driver *Alist) Login(account *model.Account) error {
var resp BaseResp
_, err := base.RestyClient.R().SetResult(&resp).
SetHeader("Authorization", account.AccessToken).
Get(account.SiteUrl + "/api/admin/login")
Get(account.SiteUrl + "/api/admin/verify")
if err != nil {
return err
}
+2 -1
View File
@@ -8,7 +8,9 @@ import (
_ "github.com/Xhofe/alist/drivers/alidrive"
_ "github.com/Xhofe/alist/drivers/alist"
_ "github.com/Xhofe/alist/drivers/baidu"
_ "github.com/Xhofe/alist/drivers/baiduphoto"
"github.com/Xhofe/alist/drivers/base"
_ "github.com/Xhofe/alist/drivers/chaoxing"
_ "github.com/Xhofe/alist/drivers/ftp"
_ "github.com/Xhofe/alist/drivers/google"
_ "github.com/Xhofe/alist/drivers/lanzou"
@@ -25,7 +27,6 @@ import (
_ "github.com/Xhofe/alist/drivers/webdav"
_ "github.com/Xhofe/alist/drivers/xunlei"
_ "github.com/Xhofe/alist/drivers/yandex"
_ "github.com/Xhofe/alist/drivers/baiduphoto"
log "github.com/sirupsen/logrus"
"strings"
)
+90
View File
@@ -0,0 +1,90 @@
package template
import (
"errors"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/go-resty/resty/v2"
"path"
)
func LoginOrRefreshToken(account *model.Account) error {
return nil
}
func Request(u string, method int, headers, query, form map[string]string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeaders(map[string]string{
"Authorization": "Bearer" + account.AccessToken,
"Accept": "application/json, text/plain, */*",
})
if headers != nil {
req.SetHeaders(headers)
}
if query != nil {
req.SetQueryParams(query)
}
if form != nil {
req.SetFormData(form)
}
if data != nil {
req.SetBody(data)
}
if resp != nil {
req.SetResult(resp)
}
var e Resp
var err error
var res *resty.Response
req.SetError(&e)
switch method {
case base.Get:
res, err = req.Get(u)
case base.Post:
res, err = req.Post(u)
case base.Delete:
res, err = req.Delete(u)
case base.Patch:
res, err = req.Patch(u)
case base.Put:
res, err = req.Put(u)
default:
return nil, base.ErrNotSupport
}
if err != nil {
return nil, err
}
if e.Code >= 400 {
if e.Code == 401 {
err = LoginOrRefreshToken(account)
if err != nil {
return nil, err
}
return Request(u, method, headers, query, form, data, resp, account)
}
return nil, errors.New(e.Message)
}
return res.Body(), nil
}
func (driver ChaoxingDrive) formatFile(f *File) *model.File {
file := model.File{
Id: f.Id,
Name: f.FileName,
Size: f.Size,
Driver: driver.Config().Name,
UpdatedAt: f.UpdatedAt,
}
if f.File {
file.Type = utils.GetFileType(path.Ext(f.FileName))
} else {
file.Type = conf.FOLDER
}
return &file
}
func init() {
base.RegisterDriver(&ChaoxingDrive{})
}
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
package template
import "time"
// write all struct here
// TYPE_CX_FILE type=1 文件
var TYPE_CX_FILE = int64(1)
// TYPE_CX_FOLDER type=2 文件夹
var TYPE_CX_FOLDER = int64(2)
// TYPE_CX_SHARED_ROOT type=4 共享文件的根目录
var TYPE_CX_SHARED_ROOT = int64(4)
type Resp struct {
Code int `json:"code"`
Message string `json:"message"`
}
type File struct {
Id string `json:"id"`
FileName string `json:"file_name"`
Size int64 `json:"size"`
File bool `json:"file"`
UpdatedAt *time.Time `json:"updated_at"`
}
+151
View File
@@ -0,0 +1,151 @@
package template
import (
"encoding/json"
"fmt"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/drivers/base"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/bitly/go-simplejson"
"github.com/go-resty/resty/v2"
"regexp"
"strconv"
"strings"
"time"
)
// write util func here, such as cal sign
var chaoxingClient = resty.New()
var form_login_fmt = "fid=-1&uname=%s&password=%s&t=true&forbidotherlogin=0&validate=&doubleFactorLogin=0"
var api_list_root = "https://pan-yz.chaoxing.com/opt/listres?page=1&size=%d&enc=%s"
var api_list_file = "https://pan-yz.chaoxing.com/opt/listres?puid=%s&shareid=%s&parentId=%s&page=1&size=%d&enc=%s"
var api_list_shared_root = "https://pan-yz.chaoxing.com/opt/listres?puid=0&shareid=-1&parentId=0&page=1&size=%d&enc=%s"
var reg_enc_fmt = regexp.MustCompile("enc[ ]*=\"(.*)\"")
func (driver ChaoxingDrive) Login(account *model.Account) error {
url := "https://passport2.chaoxing.com/fanyalogin"
var resp base.Json
var err Resp
req_body := fmt.Sprintf(form_login_fmt, account.Username, account.Password)
loginReq, e := chaoxingClient.R().SetBody(req_body).
SetResult(&resp).SetError(&err).
SetHeader("Content-Length", strconv.FormatInt(int64(len(req_body)), 10)).
SetHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8").
SetHeader("Host", "passport2.chaoxing.com").
SetHeader("User-Agent", " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36").
SetHeader("X-Requested-With", "XMLHttpRequest").
Post(url)
if e != nil {
return e
}
account.AccessToken = ""
for _, cookie := range loginReq.Cookies() {
//route=9d169c0aea4b7c89fa0d073417b5645f;
account.AccessToken += fmt.Sprintf("%s=%s; ", cookie.Name, cookie.Value)
}
return nil
}
func (driver ChaoxingDrive) GetEnc(account *model.Account) error {
url := "https://pan-yz.chaoxing.com/"
encReq, e := chaoxingClient.R().SetHeader("Cookie", account.AccessToken).Get(url)
if e != nil {
return e
}
//直接读取响应
sresp := string(encReq.Body())
submatch := reg_enc_fmt.FindAllStringSubmatch(sresp, 1)
//第一次获取失败,可能是未登录
if len(submatch) == 0 {
e = driver.Login(account)
if e != nil {
return e
}
encReq, e = chaoxingClient.R().SetHeader("Cookie", account.AccessToken).Get(url)
if e != nil {
return e
}
sresp = string(encReq.Body())
submatch = reg_enc_fmt.FindAllStringSubmatch(sresp, 1)
if len(submatch) == 0 {
account.Status = "failed"
return fmt.Errorf("登录失败,服务器返回信息:%s", sresp)
}
}
enc := submatch[0][1]
account.AccessSecret = enc
account.Status = "work"
return nil
}
func (driver ChaoxingDrive) ListFile(folder_id string, account *model.Account) ([]model.File, error) {
var url string
//按规则解析 id 号
folder_id_info := strings.Split(folder_id, "_")
if len(folder_id_info) == 3 {
folder_id = folder_id_info[0]
folder_puid := folder_id_info[1]
folder_shareid := folder_id_info[2]
if folder_id == "0" {
//访问“共享给我的文件夹”
url = fmt.Sprintf(api_list_shared_root, account.Limit, account.AccessSecret)
} else {
//访问其他目录
url = fmt.Sprintf(api_list_file, folder_puid, folder_shareid, folder_id, account.Limit, account.AccessSecret)
}
} else {
//id无法解析为三段,应当是访问根目录(此时为 "")
url = fmt.Sprintf(api_list_root, account.Limit, account.AccessSecret)
}
listFileReq, e := chaoxingClient.R().SetHeader("Cookie", account.AccessToken).Post(url)
resp, e := simplejson.NewJson(listFileReq.Body())
if e != nil || resp == nil {
return nil, e
}
files := make([]model.File, 0)
array, _ := resp.Get("list").Array()
for _, file := range array {
var f = model.File{}
file_ := file.(map[string]interface{})
//f.Id = file_["id"].(string)
f.Id = fmt.Sprintf("%s_%s_%s", file_["id"].(string), file_["puid"].(json.Number).String(), file_["shareid"].(json.Number).String())
f.Name = file_["name"].(string)
f_server_type, _ := file_["type"].(json.Number).Int64()
if f_server_type != TYPE_CX_SHARED_ROOT {
f.Size, _ = file_["filesize"].(json.Number).Int64()
}
// 为文件分配类型
switch f_server_type {
case TYPE_CX_FILE:
{
f.Type = utils.GetFileType(file_["suffix"].(string))
}
case TYPE_CX_FOLDER:
f.Type = conf.FOLDER
case TYPE_CX_SHARED_ROOT:
f.Type = conf.FOLDER
}
modifyDate, e := time.Parse("2006-01-02 15:04:05", file_["modifyDate"].(string))
if e == nil {
f.UpdatedAt = &modifyDate
}
f.Thumbnail = file_["thumbnail"].(string)
files = append(files, f)
}
return files, nil
}
+12 -1
View File
@@ -5,6 +5,7 @@ go 1.18
require (
github.com/aws/aws-sdk-go v1.27.0
github.com/caarlos0/env/v6 v6.9.1
github.com/casdoor/casdoor-go-sdk v0.7.0
github.com/eko/gocache/v2 v2.1.0
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.7.4
@@ -24,7 +25,12 @@ require (
gorm.io/gorm v1.23.1
)
require github.com/kr/fs v0.1.0 // indirect
require (
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
github.com/kr/fs v0.1.0 // indirect
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect
google.golang.org/appengine v1.6.6 // indirect
)
require (
github.com/fatih/color v1.13.0
@@ -81,3 +87,8 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3 // indirect
)
require (
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
)
+252
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -4,14 +4,9 @@ import (
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/utils"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func Login(c *gin.Context) {
SuccessResp(c)
}
func CheckParent(path string, password string) bool {
meta, err := model.GetMetaByPath(path)
if err == nil {
+69
View File
@@ -0,0 +1,69 @@
package controllers
import (
"fmt"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/server/common"
"github.com/Xhofe/alist/utils"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
"github.com/gin-gonic/gin"
"net/http"
)
type OAuthReq struct {
Code string `json:"code"`
State string `json:"state"`
}
func Verify(c *gin.Context) {
token := c.GetHeader("Authorization")
if token != conf.Token {
common.ErrorStrResp(c, "Invalid token", 401)
return
}
common.SuccessResp(c)
}
func GetRedirectUrl(c *gin.Context) {
if !conf.GetBool("Enable Casdoor") {
common.ErrorStrResp(c, "Casdoor is not enabled", 1001)
return
}
redirectUri := generateRedirectUri(c.Request)
common.SuccessResp(c, utils.GetSignInUrl(redirectUri))
}
func generateRedirectUri(r *http.Request) string {
protocol := "http"
host := r.Host
if r.TLS != nil {
protocol = "https"
}
return fmt.Sprintf("%s://%s/@manage", protocol, host)
}
func OAuth(c *gin.Context) {
var req OAuthReq
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 401)
return
}
if req.Code == "" || req.State == "" {
common.ErrorStrResp(c, "Invalid code or state", 400)
return
}
token, err := casdoorsdk.GetOAuthToken(req.Code, req.State)
if err != nil {
common.ErrorResp(c, err, 401)
return
}
_, err = casdoorsdk.ParseJwtToken(token.AccessToken)
if err != nil {
common.ErrorResp(c, err, 401)
return
}
common.SuccessResp(c, conf.Token)
}

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