mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-10 01:56:49 +08:00
Compare commits
126 Commits
Author | SHA1 | Date | |
---|---|---|---|
19d351d157 | |||
d0751bf2fa | |||
290cc60f00 | |||
6a1ec51978 | |||
dffa68cbce | |||
fad209a7a3 | |||
8b222ce2e3 | |||
c5293f428d | |||
146aec9ee8 | |||
50a52de856 | |||
8f7a8d7d4f | |||
23f3fe1e3c | |||
59ff5e02ab | |||
8d41508d6b | |||
04f70cf012 | |||
83724c73f9 | |||
33e419e133 | |||
b832c304ae | |||
4c7f6fda37 | |||
e4a54fe375 | |||
87da3dad76 | |||
44ad88353f | |||
a955fb57d6 | |||
d2960ad66b | |||
5243aabf43 | |||
d3a2c2a66e | |||
0a9058a585 | |||
225719810b | |||
c634d4a891 | |||
3dc01ec85d | |||
a7324f1da1 | |||
6da452d7e0 | |||
5abcf913e6 | |||
58455e688e | |||
4d6f68eddc | |||
67f3c5a489 | |||
9c48582e0c | |||
645c631db9 | |||
3128e68df4 | |||
2247c6a883 | |||
04709f731b | |||
ebe1887e8b | |||
a7a8805713 | |||
ceabbe27b4 | |||
7393b90155 | |||
0098c05fb3 | |||
34324d9f72 | |||
28b381e01e | |||
40039e0412 | |||
116420adb2 | |||
07c1e3b836 | |||
a447d64bf2 | |||
4116b1d305 | |||
1490044295 | |||
79f2af405a | |||
575a248c41 | |||
7083904634 | |||
3d50255060 | |||
e295da774f | |||
a3cee496b4 | |||
084a5c3e6b | |||
6670450439 | |||
e1331f314d | |||
604033aa02 | |||
729c20393c | |||
a90b27b74a | |||
5707e38912 | |||
ed959bd8c7 | |||
b6cdc46023 | |||
c661a57cb2 | |||
8456b7f7c4 | |||
e8d2906e3c | |||
1edb91b3a3 | |||
94b6eb803d | |||
cfce5289ed | |||
10f1c37730 | |||
6035b98653 | |||
e158b58ffa | |||
a399184cfc | |||
2f9f946c87 | |||
d8b60f838e | |||
7599e2715a | |||
35676455bc | |||
8128671c8c | |||
ee54dec3b3 | |||
d278bc9651 | |||
b23bd0b189 | |||
409be85264 | |||
0395b7e1a9 | |||
4536fd0636 | |||
af9ae7dbb7 | |||
e266696b32 | |||
e108d26ec7 | |||
349ce7f1d4 | |||
8da50b7893 | |||
2394c8e2b4 | |||
c62983d734 | |||
5948782cdd | |||
674d1619dd | |||
11b8b65ca0 | |||
411d76798d | |||
7b0b426a76 | |||
a383af0ebc | |||
f02875e1b1 | |||
e2921419b9 | |||
42864700ec | |||
c1fe547939 | |||
267833d9f9 | |||
2d3d1167bb | |||
ef5abdfa8f | |||
580d43101e | |||
fdf2b880cb | |||
80a2263b18 | |||
1f11d22c1c | |||
b6988286b5 | |||
64f787fab5 | |||
39c6bd5850 | |||
7312c5ce3c | |||
0bc5b90218 | |||
f3b3376a3c | |||
feec6abd88 | |||
c50042c85a | |||
ef4c3833a4 | |||
67a5adf585 | |||
08a1e7ae32 | |||
7d979cbaf0 |
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@ -34,7 +34,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: '14.17.0'
|
node-version: 16
|
||||||
# cache
|
# cache
|
||||||
- uses: c-hive/gha-yarn-cache@v2
|
- uses: c-hive/gha-yarn-cache@v2
|
||||||
with:
|
with:
|
||||||
@ -89,7 +89,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 16
|
||||||
|
|
||||||
- name: Fetch Previous version
|
- name: Fetch Previous version
|
||||||
id: get-previous-tag
|
id: get-previous-tag
|
||||||
@ -125,26 +125,36 @@ jobs:
|
|||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' &&steps.should_push.outputs.push=='true'
|
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
|
||||||
|
|
||||||
- name: Push to Docker Hub
|
- name: Push to Docker Hub
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||||
with:
|
with:
|
||||||
target: STANDARD
|
target: STANDARD
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
|
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
|
||||||
|
|
||||||
- name: Push All In One Version to Docker Hub
|
- name: Push All In One Version to Docker Hub
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
|
||||||
with:
|
with:
|
||||||
target: ALLINONE
|
target: ALLINONE
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
|
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,3 +27,6 @@ logs/
|
|||||||
files/
|
files/
|
||||||
lastupdate.tmp
|
lastupdate.tmp
|
||||||
commentsRouter*.go
|
commentsRouter*.go
|
||||||
|
|
||||||
|
# ignore build result
|
||||||
|
casdoor
|
20
Dockerfile
20
Dockerfile
@ -2,7 +2,7 @@ FROM node:16.13.0 AS FRONT
|
|||||||
WORKDIR /web
|
WORKDIR /web
|
||||||
COPY ./web .
|
COPY ./web .
|
||||||
RUN yarn config set registry https://registry.npmmirror.com
|
RUN yarn config set registry https://registry.npmmirror.com
|
||||||
RUN yarn install && yarn run build
|
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
|
||||||
|
|
||||||
|
|
||||||
FROM golang:1.17.5 AS BACK
|
FROM golang:1.17.5 AS BACK
|
||||||
@ -13,16 +13,26 @@ RUN ./build.sh
|
|||||||
|
|
||||||
FROM alpine:latest AS STANDARD
|
FROM alpine:latest AS STANDARD
|
||||||
LABEL MAINTAINER="https://casdoor.org/"
|
LABEL MAINTAINER="https://casdoor.org/"
|
||||||
|
ARG USER=casdoor
|
||||||
|
|
||||||
RUN sed -i 's/https/http/' /etc/apk/repositories
|
RUN sed -i 's/https/http/' /etc/apk/repositories
|
||||||
|
RUN apk add --update sudo
|
||||||
RUN apk add curl
|
RUN apk add curl
|
||||||
RUN apk add ca-certificates && update-ca-certificates
|
RUN apk add ca-certificates && update-ca-certificates
|
||||||
|
|
||||||
|
RUN adduser -D $USER -u 1000 \
|
||||||
|
&& echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER \
|
||||||
|
&& chmod 0440 /etc/sudoers.d/$USER \
|
||||||
|
&& mkdir logs \
|
||||||
|
&& chown -R $USER:$USER logs
|
||||||
|
|
||||||
|
USER 1000
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
COPY --from=BACK /go/src/casdoor/server ./server
|
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server ./server
|
||||||
COPY --from=BACK /go/src/casdoor/swagger ./swagger
|
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
|
||||||
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf
|
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
|
||||||
COPY --from=FRONT /web/build ./web/build
|
COPY --from=FRONT --chown=$USER:$USER /web/build ./web/build
|
||||||
|
|
||||||
ENTRYPOINT ["/server"]
|
ENTRYPOINT ["/server"]
|
||||||
|
|
||||||
|
|
||||||
|
25
README.md
25
README.md
@ -8,7 +8,7 @@
|
|||||||
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
|
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
|
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
|
||||||
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casbin/jcasbin/workflows/build/badge.svg?style=flat-square">
|
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/casdoor/casdoor/releases/latest">
|
<a href="https://github.com/casdoor/casdoor/releases/latest">
|
||||||
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
|
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casdoor.svg">
|
||||||
@ -42,47 +42,34 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Online demo
|
## Online demo
|
||||||
|
|
||||||
- International: https://door.casdoor.org (read-only)
|
- International: https://door.casdoor.org (read-only)
|
||||||
- Asian mirror: https://door.casdoor.com (read-only)
|
- Asian mirror: https://door.casdoor.com (read-only)
|
||||||
- Asian mirror: https://demo.casdoor.com (read-write, will restore for every 5 minutes)
|
- Asian mirror: https://demo.casdoor.com (read-write, will restore for every 5 minutes)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- International: https://casdoor.org
|
- International: https://casdoor.org
|
||||||
- Asian mirror: https://docs.casdoor.cn
|
- Asian mirror: https://casdoor.cn
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
- By source code: https://casdoor.org/docs/basic/server-installation
|
- By source code: https://casdoor.org/docs/basic/server-installation
|
||||||
- By Docker: https://casdoor.org/docs/basic/try-with-docker
|
- By Docker: https://casdoor.org/docs/basic/try-with-docker
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## How to connect to Casdoor?
|
## How to connect to Casdoor?
|
||||||
|
|
||||||
https://casdoor.org/docs/how-to-connect/overview
|
https://casdoor.org/docs/how-to-connect/overview
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Casdoor Public API
|
## Casdoor Public API
|
||||||
|
|
||||||
- Docs: https://casdoor.org/docs/basic/public-api
|
- Docs: https://casdoor.org/docs/basic/public-api
|
||||||
- Swagger: https://door.casdoor.com/swagger
|
- Swagger: https://door.casdoor.com/swagger
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Integrations
|
## Integrations
|
||||||
|
|
||||||
https://casdoor.org/docs/integration/apisix
|
https://casdoor.org/docs/category/integrations
|
||||||
|
|
||||||
|
|
||||||
## How to contact?
|
## How to contact?
|
||||||
|
|
||||||
@ -90,17 +77,13 @@ https://casdoor.org/docs/integration/apisix
|
|||||||
- Forum: https://forum.casbin.com
|
- Forum: https://forum.casbin.com
|
||||||
- Contact: https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e
|
- Contact: https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
|
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
|
||||||
|
|
||||||
### I18n translation
|
### I18n translation
|
||||||
|
|
||||||
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the ```web/``` directory, please remember to add what you have added to the ```web/src/locales/en/data.json``` file.
|
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
9
SECURITY.md
Normal file
9
SECURITY.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
We are grateful for security researchers and users reporting a vulnerability to us first. To ensure that your request is handled in a timely manner and we can keep users safe, please follow the below guidelines.
|
||||||
|
|
||||||
|
- **Please do not report security vulnerabilities directly on GitHub.**
|
||||||
|
|
||||||
|
- To report a vulnerability, please email [admin@casdoor.org](admin@casdoor.org).
|
@ -15,10 +15,14 @@
|
|||||||
package authz
|
package authz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/casbin/casbin/v2"
|
"github.com/casbin/casbin/v2"
|
||||||
"github.com/casbin/casbin/v2/model"
|
"github.com/casbin/casbin/v2/model"
|
||||||
xormadapter "github.com/casbin/xorm-adapter/v2"
|
xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
stringadapter "github.com/qiangmzsx/string-adapter/v2"
|
stringadapter "github.com/qiangmzsx/string-adapter/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +32,7 @@ func InitAuthz() {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
a, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "casbin_rule", tableNamePrefix, true)
|
a, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName()+conf.GetConfigString("dbName"), "casbin_rule", tableNamePrefix, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -87,6 +91,7 @@ p, *, *, GET, /api/get-organization-applications, *, *
|
|||||||
p, *, *, GET, /api/get-user, *, *
|
p, *, *, GET, /api/get-user, *, *
|
||||||
p, *, *, GET, /api/get-user-application, *, *
|
p, *, *, GET, /api/get-user-application, *, *
|
||||||
p, *, *, GET, /api/get-resources, *, *
|
p, *, *, GET, /api/get-resources, *, *
|
||||||
|
p, *, *, GET, /api/get-records, *, *
|
||||||
p, *, *, GET, /api/get-product, *, *
|
p, *, *, GET, /api/get-product, *, *
|
||||||
p, *, *, POST, /api/buy-product, *, *
|
p, *, *, POST, /api/buy-product, *, *
|
||||||
p, *, *, GET, /api/get-payment, *, *
|
p, *, *, GET, /api/get-payment, *, *
|
||||||
@ -107,6 +112,8 @@ p, *, *, POST, /api/acs, *, *
|
|||||||
p, *, *, GET, /api/saml/metadata, *, *
|
p, *, *, GET, /api/saml/metadata, *, *
|
||||||
p, *, *, *, /cas, *, *
|
p, *, *, *, /cas, *, *
|
||||||
p, *, *, *, /api/webauthn, *, *
|
p, *, *, *, /api/webauthn, *, *
|
||||||
|
p, *, *, GET, /api/get-release, *, *
|
||||||
|
p, *, *, GET, /api/get-default-application, *, *
|
||||||
`
|
`
|
||||||
|
|
||||||
sa := stringadapter.NewAdapter(ruleText)
|
sa := stringadapter.NewAdapter(ruleText)
|
||||||
@ -127,6 +134,18 @@ p, *, *, *, /api/webauthn, *, *
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||||
|
if conf.IsDemoMode() {
|
||||||
|
if !isAllowedInDemoMode(subOwner, subName, method, urlPath, objOwner, objName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := fmt.Sprintf("%s/%s", subOwner, subName)
|
||||||
|
user := object.GetUser(userId)
|
||||||
|
if user != nil && user.IsAdmin && subOwner == objOwner {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName)
|
res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -134,3 +153,22 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||||
|
if method == "POST" {
|
||||||
|
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/send-verification-code" {
|
||||||
|
return true
|
||||||
|
} else if urlPath == "/api/update-user" {
|
||||||
|
// Allow ordinary users to update their own information
|
||||||
|
if subOwner == objOwner && subName == objName && !(subOwner == "built-in" && subName == "admin") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If method equals GET
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
6
build.sh
6
build.sh
@ -1,11 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#try to connect to google to determine whether user need to use proxy
|
#try to connect to google to determine whether user need to use proxy
|
||||||
curl www.google.com -o /dev/null --connect-timeout 5 2 > /dev/null
|
curl www.google.com -o /dev/null --connect-timeout 5 2> /dev/null
|
||||||
if [ $? == 0 ]
|
if [ $? == 0 ]
|
||||||
then
|
then
|
||||||
echo "Successfully connected to Google, no need to use Go proxy"
|
echo "Successfully connected to Google, no need to use Go proxy"
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
|
|
||||||
else
|
else
|
||||||
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
|
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOPROXY=https://goproxy.cn,direct go build -ldflags="-w -s" -o server .
|
export GOPROXY="https://goproxy.cn,direct"
|
||||||
fi
|
fi
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
|
||||||
|
@ -16,4 +16,7 @@ verificationCodeTimeout = 10
|
|||||||
initScore = 2000
|
initScore = 2000
|
||||||
logPostOnly = true
|
logPostOnly = true
|
||||||
origin =
|
origin =
|
||||||
staticBaseUrl = "https://cdn.casbin.org"
|
staticBaseUrl = "https://cdn.casbin.org"
|
||||||
|
isDemoMode = false
|
||||||
|
batchSize = 100
|
||||||
|
ldapServerPort = 389
|
||||||
|
49
conf/conf.go
49
conf/conf.go
@ -21,14 +21,35 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// this array contains the beego configuration items that may be modified via env
|
||||||
|
presetConfigItems := []string{"httpport", "appname"}
|
||||||
|
for _, key := range presetConfigItems {
|
||||||
|
if value, ok := os.LookupEnv(key); ok {
|
||||||
|
err := beego.AppConfig.Set(key, value)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetConfigString(key string) string {
|
func GetConfigString(key string) string {
|
||||||
if value, ok := os.LookupEnv(key); ok {
|
if value, ok := os.LookupEnv(key); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
return beego.AppConfig.String(key)
|
|
||||||
|
res := beego.AppConfig.String(key)
|
||||||
|
if res == "" {
|
||||||
|
if key == "staticBaseUrl" {
|
||||||
|
res = "https://cdn.casbin.org"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigBool(key string) (bool, error) {
|
func GetConfigBool(key string) (bool, error) {
|
||||||
@ -47,17 +68,7 @@ func GetConfigInt64(key string) (int64, error) {
|
|||||||
return num, err
|
return num, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func GetConfigDataSourceName() string {
|
||||||
// this array contains the beego configuration items that may be modified via env
|
|
||||||
presetConfigItems := []string{"httpport", "appname"}
|
|
||||||
for _, key := range presetConfigItems {
|
|
||||||
if value, ok := os.LookupEnv(key); ok {
|
|
||||||
beego.AppConfig.Set(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBeegoConfDataSourceName() string {
|
|
||||||
dataSourceName := GetConfigString("dataSourceName")
|
dataSourceName := GetConfigString("dataSourceName")
|
||||||
|
|
||||||
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
|
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
|
||||||
@ -72,3 +83,15 @@ func GetBeegoConfDataSourceName() string {
|
|||||||
|
|
||||||
return dataSourceName
|
return dataSourceName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsDemoMode() bool {
|
||||||
|
return strings.ToLower(GetConfigString("isDemoMode")) == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfigBatchSize() int {
|
||||||
|
res, err := strconv.Atoi(GetConfigString("batchSize"))
|
||||||
|
if err != nil {
|
||||||
|
res = 100
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,7 +105,8 @@ func (c *ApiController) Signup() {
|
|||||||
var form RequestForm
|
var form RequestForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
||||||
@ -156,6 +157,12 @@ func (c *ApiController) Signup() {
|
|||||||
username = id
|
username = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initScore, err := getInitScore()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
user := &object.User{
|
user := &object.User{
|
||||||
Owner: form.Organization,
|
Owner: form.Organization,
|
||||||
Name: username,
|
Name: username,
|
||||||
@ -171,7 +178,7 @@ func (c *ApiController) Signup() {
|
|||||||
Affiliation: form.Affiliation,
|
Affiliation: form.Affiliation,
|
||||||
IdCard: form.IdCard,
|
IdCard: form.IdCard,
|
||||||
Region: form.Region,
|
Region: form.Region,
|
||||||
Score: getInitScore(),
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
IsGlobalAdmin: false,
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
@ -251,15 +258,14 @@ func (c *ApiController) Logout() {
|
|||||||
// @Success 200 {object} controllers.Response The Response object
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
// @router /get-account [get]
|
// @router /get-account [get]
|
||||||
func (c *ApiController) GetAccount() {
|
func (c *ApiController) GetAccount() {
|
||||||
userId, ok := c.RequireSignedIn()
|
user, ok := c.RequireSignedInUser()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := object.GetUser(userId)
|
managedAccounts := c.Input().Get("managedAccounts")
|
||||||
if user == nil {
|
if managedAccounts == "1" {
|
||||||
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
|
user = object.ExtendManagedAccountsWithUser(user)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
|
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
|
||||||
@ -282,18 +288,16 @@ func (c *ApiController) GetAccount() {
|
|||||||
// @Success 200 {object} object.Userinfo The Response object
|
// @Success 200 {object} object.Userinfo The Response object
|
||||||
// @router /userinfo [get]
|
// @router /userinfo [get]
|
||||||
func (c *ApiController) GetUserinfo() {
|
func (c *ApiController) GetUserinfo() {
|
||||||
userId, ok := c.RequireSignedIn()
|
user, ok := c.RequireSignedInUser()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scope, aud := c.GetSessionOidc()
|
scope, aud := c.GetSessionOidc()
|
||||||
host := c.Ctx.Request.Host
|
host := c.Ctx.Request.Host
|
||||||
resp, err := object.GetUserInfo(userId, scope, aud, host)
|
userInfo := object.GetUserInfo(user, scope, aud, host)
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
c.Data["json"] = userInfo
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Data["json"] = resp
|
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -111,8 +111,7 @@ func (c *ApiController) GetOrganizationApplications() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var applications []*object.Application
|
applications := object.GetApplicationsByOrganizationName(owner, organization)
|
||||||
applications = object.GetApplicationsByOrganizationName(owner, organization)
|
|
||||||
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
@ -131,7 +130,8 @@ func (c *ApiController) UpdateApplication() {
|
|||||||
var application object.Application
|
var application object.Application
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
|
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
|
||||||
@ -149,7 +149,8 @@ func (c *ApiController) AddApplication() {
|
|||||||
var application object.Application
|
var application object.Application
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
|
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
|
||||||
@ -167,7 +168,8 @@ func (c *ApiController) DeleteApplication() {
|
|||||||
var application object.Application
|
var application object.Application
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteApplication(&application))
|
c.Data["json"] = wrapActionResponse(object.DeleteApplication(&application))
|
||||||
|
@ -344,7 +344,7 @@ func (c *ApiController) Login() {
|
|||||||
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
|
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user != nil && user.IsDeleted == false {
|
if user != nil && !user.IsDeleted {
|
||||||
// Sign in via OAuth (want to sign up but already have account)
|
// Sign in via OAuth (want to sign up but already have account)
|
||||||
|
|
||||||
if user.IsForbidden {
|
if user.IsForbidden {
|
||||||
@ -384,6 +384,12 @@ func (c *ApiController) Login() {
|
|||||||
|
|
||||||
properties := map[string]string{}
|
properties := map[string]string{}
|
||||||
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
|
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
|
||||||
|
initScore, err := getInitScore()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
user = &object.User{
|
user = &object.User{
|
||||||
Owner: application.Organization,
|
Owner: application.Organization,
|
||||||
Name: userInfo.Username,
|
Name: userInfo.Username,
|
||||||
@ -394,7 +400,7 @@ func (c *ApiController) Login() {
|
|||||||
Avatar: userInfo.AvatarUrl,
|
Avatar: userInfo.AvatarUrl,
|
||||||
Address: []string{},
|
Address: []string{},
|
||||||
Email: userInfo.Email,
|
Email: userInfo.Email,
|
||||||
Score: getInitScore(),
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
IsGlobalAdmin: false,
|
||||||
IsForbidden: false,
|
IsForbidden: false,
|
||||||
|
@ -18,7 +18,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
|
"github.com/beego/beego/logs"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -58,6 +59,7 @@ func (c *ApiController) IsGlobalAdmin() bool {
|
|||||||
func (c *ApiController) GetSessionUsername() string {
|
func (c *ApiController) GetSessionUsername() string {
|
||||||
// check if user session expired
|
// check if user session expired
|
||||||
sessionData := c.GetSessionData()
|
sessionData := c.GetSessionData()
|
||||||
|
|
||||||
if sessionData != nil &&
|
if sessionData != nil &&
|
||||||
sessionData.ExpireTime != 0 &&
|
sessionData.ExpireTime != 0 &&
|
||||||
sessionData.ExpireTime < time.Now().Unix() {
|
sessionData.ExpireTime < time.Now().Unix() {
|
||||||
@ -120,7 +122,8 @@ func (c *ApiController) GetSessionData() *SessionData {
|
|||||||
sessionData := &SessionData{}
|
sessionData := &SessionData{}
|
||||||
err := util.JsonToStruct(session.(string), sessionData)
|
err := util.JsonToStruct(session.(string), sessionData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logs.Error("GetSessionData failed, error: %s", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return sessionData
|
return sessionData
|
||||||
|
94
controllers/casbin_adapter.go
Normal file
94
controllers/casbin_adapter.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/beego/beego/utils/pagination"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *ApiController) GetCasbinAdapters() {
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
limit := c.Input().Get("pageSize")
|
||||||
|
page := c.Input().Get("p")
|
||||||
|
field := c.Input().Get("field")
|
||||||
|
value := c.Input().Get("value")
|
||||||
|
sortField := c.Input().Get("sortField")
|
||||||
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
if limit == "" || page == "" {
|
||||||
|
c.Data["json"] = object.GetCasbinAdapters(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, field, value)))
|
||||||
|
adapters := object.GetPaginationCasbinAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
c.ResponseOk(adapters, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) GetCasbinAdapter() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
c.Data["json"] = object.GetCasbinAdapter(id)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) UpdateCasbinAdapter() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var casbinAdapter object.CasbinAdapter
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.UpdateCasbinAdapter(id, &casbinAdapter))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) AddCasbinAdapter() {
|
||||||
|
var casbinAdapter object.CasbinAdapter
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddCasbinAdapter(&casbinAdapter))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) DeleteCasbinAdapter() {
|
||||||
|
var casbinAdapter object.CasbinAdapter
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.DeleteCasbinAdapter(&casbinAdapter))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) SyncPolicies() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
adapter := object.GetCasbinAdapter(id)
|
||||||
|
|
||||||
|
c.Data["json"] = object.SyncPolicies(adapter)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateCert() {
|
|||||||
var cert object.Cert
|
var cert object.Cert
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert))
|
c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddCert() {
|
|||||||
var cert object.Cert
|
var cert object.Cert
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddCert(&cert))
|
c.Data["json"] = wrapActionResponse(object.AddCert(&cert))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteCert() {
|
|||||||
var cert object.Cert
|
var cert object.Cert
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert))
|
c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert))
|
||||||
|
@ -30,7 +30,8 @@ func (c *ApiController) Enforce() {
|
|||||||
var permissionRule object.PermissionRule
|
var permissionRule object.PermissionRule
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.Enforce(userId, &permissionRule)
|
c.Data["json"] = object.Enforce(userId, &permissionRule)
|
||||||
@ -47,7 +48,8 @@ func (c *ApiController) BatchEnforce() {
|
|||||||
var permissionRules []object.PermissionRule
|
var permissionRules []object.PermissionRule
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.BatchEnforce(userId, permissionRules)
|
c.Data["json"] = object.BatchEnforce(userId, permissionRules)
|
||||||
|
@ -199,7 +199,8 @@ func (c *ApiController) DeleteLdap() {
|
|||||||
var ldap object.Ldap
|
var ldap object.Ldap
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id)
|
object.GetLdapAutoSynchronizer().StopAutoSync(ldap.Id)
|
||||||
@ -217,7 +218,8 @@ func (c *ApiController) SyncLdapUsers() {
|
|||||||
var users []object.LdapRespUser
|
var users []object.LdapRespUser
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
object.UpdateLdapSyncTime(ldapId)
|
object.UpdateLdapSyncTime(ldapId)
|
||||||
@ -239,7 +241,8 @@ func (c *ApiController) CheckLdapUsersExist() {
|
|||||||
var uuids []string
|
var uuids []string
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &uuids)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &uuids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
exist := object.CheckLdapUuidExist(owner, uuids)
|
exist := object.CheckLdapUuidExist(owner, uuids)
|
||||||
|
118
controllers/ldapserver.go
Normal file
118
controllers/ldapserver.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/forestmgy/ldapserver"
|
||||||
|
"github.com/lor00x/goldap/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartLdapServer() {
|
||||||
|
server := ldapserver.NewServer()
|
||||||
|
routes := ldapserver.NewRouteMux()
|
||||||
|
|
||||||
|
routes.Bind(handleBind)
|
||||||
|
routes.Search(handleSearch).Label(" SEARCH****")
|
||||||
|
|
||||||
|
server.Handle(routes)
|
||||||
|
server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleBind(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
||||||
|
r := m.GetBindRequest()
|
||||||
|
res := ldapserver.NewBindResponse(ldapserver.LDAPResultSuccess)
|
||||||
|
|
||||||
|
if r.AuthenticationChoice() == "simple" {
|
||||||
|
bindusername, bindorg, err := object.GetNameAndOrgFromDN(string(r.Name()))
|
||||||
|
if err != "" {
|
||||||
|
log.Printf("Bind failed ,ErrMsg=%s", err)
|
||||||
|
res.SetResultCode(ldapserver.LDAPResultInvalidDNSyntax)
|
||||||
|
res.SetDiagnosticMessage("bind failed ErrMsg: " + err)
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bindpassword := string(r.AuthenticationSimple())
|
||||||
|
binduser, err := object.CheckUserPassword(bindorg, bindusername, bindpassword)
|
||||||
|
if err != "" {
|
||||||
|
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
||||||
|
res.SetResultCode(ldapserver.LDAPResultInvalidCredentials)
|
||||||
|
res.SetDiagnosticMessage("invalid credentials ErrMsg: " + err)
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if bindorg == "built-in" {
|
||||||
|
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
|
||||||
|
} else if binduser.IsAdmin {
|
||||||
|
m.Client.IsOrgAdmin = true
|
||||||
|
}
|
||||||
|
m.Client.IsAuthenticated = true
|
||||||
|
m.Client.UserName = bindusername
|
||||||
|
m.Client.OrgName = bindorg
|
||||||
|
} else {
|
||||||
|
res.SetResultCode(ldapserver.LDAPResultAuthMethodNotSupported)
|
||||||
|
res.SetDiagnosticMessage("Authentication method not supported,Please use Simple Authentication")
|
||||||
|
}
|
||||||
|
w.Write(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
||||||
|
res := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultSuccess)
|
||||||
|
if !m.Client.IsAuthenticated {
|
||||||
|
res.SetResultCode(ldapserver.LDAPResultUnwillingToPerform)
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := m.GetSearchRequest()
|
||||||
|
if r.FilterString() == "(objectClass=*)" {
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
name, org, errCode := object.GetUserNameAndOrgFromBaseDnAndFilter(string(r.BaseObject()), r.FilterString())
|
||||||
|
if errCode != ldapserver.LDAPResultSuccess {
|
||||||
|
res.SetResultCode(errCode)
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
|
||||||
|
select {
|
||||||
|
case <-m.Done:
|
||||||
|
log.Print("Leaving handleSearch...")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
users, errCode := object.GetFilteredUsers(m, name, org)
|
||||||
|
if errCode != ldapserver.LDAPResultSuccess {
|
||||||
|
res.SetResultCode(errCode)
|
||||||
|
w.Write(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < len(users); i++ {
|
||||||
|
user := users[i]
|
||||||
|
dn := fmt.Sprintf("cn=%s,%s", user.DisplayName, string(r.BaseObject()))
|
||||||
|
e := ldapserver.NewSearchResultEntry(dn)
|
||||||
|
e.AddAttribute("cn", message.AttributeValue(user.Name))
|
||||||
|
e.AddAttribute("uid", message.AttributeValue(user.Name))
|
||||||
|
e.AddAttribute("email", message.AttributeValue(user.Email))
|
||||||
|
e.AddAttribute("mobile", message.AttributeValue(user.Phone))
|
||||||
|
// e.AddAttribute("postalAddress", message.AttributeValue(user.Address[0]))
|
||||||
|
w.Write(e)
|
||||||
|
}
|
||||||
|
w.Write(res)
|
||||||
|
}
|
@ -29,7 +29,7 @@ type LinkForm struct {
|
|||||||
// @router /unlink [post]
|
// @router /unlink [post]
|
||||||
// @Tag Login API
|
// @Tag Login API
|
||||||
func (c *ApiController) Unlink() {
|
func (c *ApiController) Unlink() {
|
||||||
userId, ok := c.RequireSignedIn()
|
user, ok := c.RequireSignedInUser()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -37,13 +37,13 @@ func (c *ApiController) Unlink() {
|
|||||||
var form LinkForm
|
var form LinkForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
providerType := form.ProviderType
|
providerType := form.ProviderType
|
||||||
|
|
||||||
// the user will be unlinked from the provider
|
// the user will be unlinked from the provider
|
||||||
unlinkedUser := form.User
|
unlinkedUser := form.User
|
||||||
user := object.GetUser(userId)
|
|
||||||
|
|
||||||
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
|
if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
|
||||||
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
|
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateModel() {
|
|||||||
var model object.Model
|
var model object.Model
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateModel(id, &model))
|
c.Data["json"] = wrapActionResponse(object.UpdateModel(id, &model))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddModel() {
|
|||||||
var model object.Model
|
var model object.Model
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddModel(&model))
|
c.Data["json"] = wrapActionResponse(object.AddModel(&model))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteModel() {
|
|||||||
var model object.Model
|
var model object.Model
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteModel(&model))
|
c.Data["json"] = wrapActionResponse(object.DeleteModel(&model))
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateOrganization() {
|
|||||||
var organization object.Organization
|
var organization object.Organization
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
|
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddOrganization() {
|
|||||||
var organization object.Organization
|
var organization object.Organization
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
|
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
|
||||||
@ -112,9 +114,31 @@ func (c *ApiController) DeleteOrganization() {
|
|||||||
var organization object.Organization
|
var organization object.Organization
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteOrganization(&organization))
|
c.Data["json"] = wrapActionResponse(object.DeleteOrganization(&organization))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDefaultApplication ...
|
||||||
|
// @Title GetDefaultApplication
|
||||||
|
// @Tag Organization API
|
||||||
|
// @Description get default application
|
||||||
|
// @Param id query string true "organization id"
|
||||||
|
// @Success 200 {object} Response The Response object
|
||||||
|
// @router /get-default-application [get]
|
||||||
|
func (c *ApiController) GetDefaultApplication() {
|
||||||
|
userId := c.GetSessionUsername()
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
application, err := object.GetDefaultApplication(id)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
maskedApplication := object.GetMaskedApplication(application, userId)
|
||||||
|
c.ResponseOk(maskedApplication)
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -95,7 +95,8 @@ func (c *ApiController) UpdatePayment() {
|
|||||||
var payment object.Payment
|
var payment object.Payment
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdatePayment(id, &payment))
|
c.Data["json"] = wrapActionResponse(object.UpdatePayment(id, &payment))
|
||||||
@ -113,7 +114,8 @@ func (c *ApiController) AddPayment() {
|
|||||||
var payment object.Payment
|
var payment object.Payment
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddPayment(&payment))
|
c.Data["json"] = wrapActionResponse(object.AddPayment(&payment))
|
||||||
@ -131,7 +133,8 @@ func (c *ApiController) DeletePayment() {
|
|||||||
var payment object.Payment
|
var payment object.Payment
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeletePayment(&payment))
|
c.Data["json"] = wrapActionResponse(object.DeletePayment(&payment))
|
||||||
@ -157,7 +160,8 @@ func (c *ApiController) NotifyPayment() {
|
|||||||
if ok {
|
if ok {
|
||||||
_, err := c.Ctx.ResponseWriter.Write([]byte("success"))
|
_, err := c.Ctx.ResponseWriter.Write([]byte("success"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Errorf("NotifyPayment() failed: %v", ok))
|
panic(fmt.Errorf("NotifyPayment() failed: %v", ok))
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -55,13 +55,12 @@ func (c *ApiController) GetPermissions() {
|
|||||||
// @Success 200 {array} object.Permission The Response object
|
// @Success 200 {array} object.Permission The Response object
|
||||||
// @router /get-permissions-by-submitter [get]
|
// @router /get-permissions-by-submitter [get]
|
||||||
func (c *ApiController) GetPermissionsBySubmitter() {
|
func (c *ApiController) GetPermissionsBySubmitter() {
|
||||||
userId, ok := c.RequireSignedIn()
|
user, ok := c.RequireSignedInUser()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
owner, username := util.GetOwnerAndNameFromId(userId)
|
permissions := object.GetPermissionsBySubmitter(user.Owner, user.Name)
|
||||||
permissions := object.GetPermissionsBySubmitter(owner, username)
|
|
||||||
c.ResponseOk(permissions, len(permissions))
|
c.ResponseOk(permissions, len(permissions))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -94,7 +93,8 @@ func (c *ApiController) UpdatePermission() {
|
|||||||
var permission object.Permission
|
var permission object.Permission
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission))
|
c.Data["json"] = wrapActionResponse(object.UpdatePermission(id, &permission))
|
||||||
@ -112,7 +112,8 @@ func (c *ApiController) AddPermission() {
|
|||||||
var permission object.Permission
|
var permission object.Permission
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddPermission(&permission))
|
c.Data["json"] = wrapActionResponse(object.AddPermission(&permission))
|
||||||
@ -130,7 +131,8 @@ func (c *ApiController) DeletePermission() {
|
|||||||
var permission object.Permission
|
var permission object.Permission
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission))
|
c.Data["json"] = wrapActionResponse(object.DeletePermission(&permission))
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -80,7 +80,8 @@ func (c *ApiController) UpdateProduct() {
|
|||||||
var product object.Product
|
var product object.Product
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateProduct(id, &product))
|
c.Data["json"] = wrapActionResponse(object.UpdateProduct(id, &product))
|
||||||
@ -98,7 +99,8 @@ func (c *ApiController) AddProduct() {
|
|||||||
var product object.Product
|
var product object.Product
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddProduct(&product))
|
c.Data["json"] = wrapActionResponse(object.AddProduct(&product))
|
||||||
@ -116,7 +118,8 @@ func (c *ApiController) DeleteProduct() {
|
|||||||
var product object.Product
|
var product object.Product
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))
|
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateProvider() {
|
|||||||
var provider object.Provider
|
var provider object.Provider
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
|
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddProvider() {
|
|||||||
var provider object.Provider
|
var provider object.Provider
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
|
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteProvider() {
|
|||||||
var provider object.Provider
|
var provider object.Provider
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
|
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -29,6 +31,11 @@ import (
|
|||||||
// @Success 200 {object} object.Record The Response object
|
// @Success 200 {object} object.Record The Response object
|
||||||
// @router /get-records [get]
|
// @router /get-records [get]
|
||||||
func (c *ApiController) GetRecords() {
|
func (c *ApiController) GetRecords() {
|
||||||
|
organization, ok := c.RequireAdmin()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit := c.Input().Get("pageSize")
|
limit := c.Input().Get("pageSize")
|
||||||
page := c.Input().Get("p")
|
page := c.Input().Get("p")
|
||||||
field := c.Input().Get("field")
|
field := c.Input().Get("field")
|
||||||
@ -40,8 +47,9 @@ func (c *ApiController) GetRecords() {
|
|||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount(field, value)))
|
filterRecord := &object.Record{Organization: organization}
|
||||||
records := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder)
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetRecordCount(field, value, filterRecord)))
|
||||||
|
records := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
|
||||||
c.ResponseOk(records, paginator.Nums())
|
c.ResponseOk(records, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,9 +67,29 @@ func (c *ApiController) GetRecordsByFilter() {
|
|||||||
record := &object.Record{}
|
record := &object.Record{}
|
||||||
err := util.JsonToStruct(body, record)
|
err := util.JsonToStruct(body, record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.GetRecordsByField(record)
|
c.Data["json"] = object.GetRecordsByField(record)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRecord
|
||||||
|
// @Title AddRecord
|
||||||
|
// @Tag Record API
|
||||||
|
// @Description add a record
|
||||||
|
// @Param body body object.Record true "The details of the record"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /add-record [post]
|
||||||
|
func (c *ApiController) AddRecord() {
|
||||||
|
var record object.Record
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &record)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddRecord(&record))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"mime"
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -72,7 +72,8 @@ func (c *ApiController) UpdateResource() {
|
|||||||
var resource object.Resource
|
var resource object.Resource
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateResource(id, &resource))
|
c.Data["json"] = wrapActionResponse(object.UpdateResource(id, &resource))
|
||||||
@ -87,7 +88,8 @@ func (c *ApiController) AddResource() {
|
|||||||
var resource object.Resource
|
var resource object.Resource
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddResource(&resource))
|
c.Data["json"] = wrapActionResponse(object.AddResource(&resource))
|
||||||
@ -102,7 +104,8 @@ func (c *ApiController) DeleteResource() {
|
|||||||
var resource object.Resource
|
var resource object.Resource
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
provider, _, ok := c.GetProviderFromContext("Storage")
|
provider, _, ok := c.GetProviderFromContext("Storage")
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateRole() {
|
|||||||
var role object.Role
|
var role object.Role
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateRole(id, &role))
|
c.Data["json"] = wrapActionResponse(object.UpdateRole(id, &role))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddRole() {
|
|||||||
var role object.Role
|
var role object.Role
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddRole(&role))
|
c.Data["json"] = wrapActionResponse(object.AddRole(&role))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteRole() {
|
|||||||
var role object.Role
|
var role object.Role
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteRole(&role))
|
c.Data["json"] = wrapActionResponse(object.DeleteRole(&role))
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateSyncer() {
|
|||||||
var syncer object.Syncer
|
var syncer object.Syncer
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
|
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddSyncer() {
|
|||||||
var syncer object.Syncer
|
var syncer object.Syncer
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddSyncer(&syncer))
|
c.Data["json"] = wrapActionResponse(object.AddSyncer(&syncer))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteSyncer() {
|
|||||||
var syncer object.Syncer
|
var syncer object.Syncer
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteSyncer(&syncer))
|
c.Data["json"] = wrapActionResponse(object.DeleteSyncer(&syncer))
|
||||||
|
82
controllers/system_info.go
Normal file
82
controllers/system_info.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SystemInfo struct {
|
||||||
|
MemoryUsed uint64 `json:"memory_used"`
|
||||||
|
MemoryTotal uint64 `json:"memory_total"`
|
||||||
|
CpuUsage []float64 `json:"cpu_usage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemInfo
|
||||||
|
// @Title GetSystemInfo
|
||||||
|
// @Tag System API
|
||||||
|
// @Description get user's system info
|
||||||
|
// @Param id query string true "The id of the user"
|
||||||
|
// @Success 200 {object} object.SystemInfo The Response object
|
||||||
|
// @router /get-system-info [get]
|
||||||
|
func (c *ApiController) GetSystemInfo() {
|
||||||
|
id := c.GetString("id")
|
||||||
|
if id == "" {
|
||||||
|
id = c.GetSessionUsername()
|
||||||
|
}
|
||||||
|
|
||||||
|
user := object.GetUser(id)
|
||||||
|
if user == nil || !user.IsGlobalAdmin {
|
||||||
|
c.ResponseError("You are not authorized to access this resource")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuUsage, err := util.GetCpuUsage()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryUsed, memoryTotal, err := util.GetMemoryUsage()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = SystemInfo{
|
||||||
|
CpuUsage: cpuUsage,
|
||||||
|
MemoryUsed: memoryUsed,
|
||||||
|
MemoryTotal: memoryTotal,
|
||||||
|
}
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GitRepoVersion
|
||||||
|
// @Title GitRepoVersion
|
||||||
|
// @Tag System API
|
||||||
|
// @Description get local github repo's latest release version info
|
||||||
|
// @Success 200 {string} local latest version hash of casdoor
|
||||||
|
// @router /get-release [get]
|
||||||
|
func (c *ApiController) GitRepoVersion() {
|
||||||
|
version, err := util.GetGitRepoVersion()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = version
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
@ -18,7 +18,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -79,7 +79,8 @@ func (c *ApiController) UpdateToken() {
|
|||||||
var token object.Token
|
var token object.Token
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
|
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
|
||||||
@ -97,7 +98,8 @@ func (c *ApiController) AddToken() {
|
|||||||
var token object.Token
|
var token object.Token
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddToken(&token))
|
c.Data["json"] = wrapActionResponse(object.AddToken(&token))
|
||||||
@ -115,7 +117,8 @@ func (c *ApiController) DeleteToken() {
|
|||||||
var token object.Token
|
var token object.Token
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteToken(&token))
|
c.Data["json"] = wrapActionResponse(object.DeleteToken(&token))
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -119,12 +119,7 @@ func (c *ApiController) GetUser() {
|
|||||||
user = object.GetUser(id)
|
user = object.GetUser(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user != nil {
|
object.ExtendUserWithRolesAndPermissions(user)
|
||||||
roles := object.GetRolesByUser(user.GetId())
|
|
||||||
user.Roles = roles
|
|
||||||
permissions := object.GetPermissionsByUser(user.GetId())
|
|
||||||
user.Permissions = permissions
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Data["json"] = object.GetMaskedUser(user)
|
c.Data["json"] = object.GetMaskedUser(user)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
@ -149,7 +144,8 @@ func (c *ApiController) UpdateUser() {
|
|||||||
var user object.User
|
var user object.User
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.DisplayName == "" {
|
if user.DisplayName == "" {
|
||||||
@ -183,7 +179,14 @@ func (c *ApiController) AddUser() {
|
|||||||
var user object.User
|
var user object.User
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := object.CheckUsername(user.Name)
|
||||||
|
if msg != "" {
|
||||||
|
c.ResponseError(msg)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
|
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
|
||||||
@ -201,7 +204,8 @@ func (c *ApiController) DeleteUser() {
|
|||||||
var user object.User
|
var user object.User
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
|
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
|
||||||
@ -220,7 +224,8 @@ func (c *ApiController) GetEmailAndPhone() {
|
|||||||
var form RequestForm
|
var form RequestForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := object.GetUserByFields(form.Organization, form.Username)
|
user := object.GetUserByFields(form.Organization, form.Username)
|
||||||
@ -306,7 +311,8 @@ func (c *ApiController) CheckUserPassword() {
|
|||||||
var user object.User
|
var user object.User
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, msg := object.CheckUserPassword(user.Owner, user.Name, user.Password)
|
_, msg := object.CheckUserPassword(user.Owner, user.Name, user.Password)
|
||||||
|
@ -24,17 +24,18 @@ import (
|
|||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func saveFile(path string, file *multipart.File) {
|
func saveFile(path string, file *multipart.File) (err error) {
|
||||||
f, err := os.Create(path)
|
f, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
_, err = io.Copy(f, *file)
|
_, err = io.Copy(f, *file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) UploadUsers() {
|
func (c *ApiController) UploadUsers() {
|
||||||
@ -43,13 +44,18 @@ func (c *ApiController) UploadUsers() {
|
|||||||
|
|
||||||
file, header, err := c.Ctx.Request.FormFile("file")
|
file, header, err := c.Ctx.Request.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
|
||||||
|
|
||||||
path := util.GetUploadXlsxPath(fileId)
|
path := util.GetUploadXlsxPath(fileId)
|
||||||
util.EnsureFileFolderExists(path)
|
util.EnsureFileFolderExists(path)
|
||||||
saveFile(path, &file)
|
err = saveFile(path, &file)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
affected := object.UploadUsers(owner, fileId)
|
affected := object.UploadUsers(owner, fileId)
|
||||||
if affected {
|
if affected {
|
||||||
|
@ -23,9 +23,8 @@ import (
|
|||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResponseOk ...
|
// ResponseJsonData ...
|
||||||
func (c *ApiController) ResponseOk(data ...interface{}) {
|
func (c *ApiController) ResponseJsonData(resp *Response, data ...interface{}) {
|
||||||
resp := Response{Status: "ok"}
|
|
||||||
switch len(data) {
|
switch len(data) {
|
||||||
case 2:
|
case 2:
|
||||||
resp.Data2 = data[1]
|
resp.Data2 = data[1]
|
||||||
@ -37,18 +36,16 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
|
|||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseOk ...
|
||||||
|
func (c *ApiController) ResponseOk(data ...interface{}) {
|
||||||
|
resp := &Response{Status: "ok"}
|
||||||
|
c.ResponseJsonData(resp, data...)
|
||||||
|
}
|
||||||
|
|
||||||
// ResponseError ...
|
// ResponseError ...
|
||||||
func (c *ApiController) ResponseError(error string, data ...interface{}) {
|
func (c *ApiController) ResponseError(error string, data ...interface{}) {
|
||||||
resp := Response{Status: "error", Msg: error}
|
resp := &Response{Status: "error", Msg: error}
|
||||||
switch len(data) {
|
c.ResponseJsonData(resp, data...)
|
||||||
case 2:
|
|
||||||
resp.Data2 = data[1]
|
|
||||||
fallthrough
|
|
||||||
case 1:
|
|
||||||
resp.Data = data[0]
|
|
||||||
}
|
|
||||||
c.Data["json"] = resp
|
|
||||||
c.ServeJSON()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTokenErrorHttpStatus ...
|
// SetTokenErrorHttpStatus ...
|
||||||
@ -78,13 +75,36 @@ func (c *ApiController) RequireSignedIn() (string, bool) {
|
|||||||
return userId, true
|
return userId, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInitScore() int {
|
// RequireSignedInUser ...
|
||||||
score, err := strconv.Atoi(conf.GetConfigString("initScore"))
|
func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
|
||||||
if err != nil {
|
userId, ok := c.RequireSignedIn()
|
||||||
panic(err)
|
if !ok {
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return score
|
user := object.GetUser(userId)
|
||||||
|
if user == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return user, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireAdmin ...
|
||||||
|
func (c *ApiController) RequireAdmin() (string, bool) {
|
||||||
|
user, ok := c.RequireSignedInUser()
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Owner == "built-in" {
|
||||||
|
return "", true
|
||||||
|
}
|
||||||
|
return user.Owner, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInitScore() (int, error) {
|
||||||
|
return strconv.Atoi(conf.GetConfigString("initScore"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {
|
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {
|
||||||
|
@ -148,17 +148,11 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
// @Title ResetEmailOrPhone
|
// @Title ResetEmailOrPhone
|
||||||
// @router /api/reset-email-or-phone [post]
|
// @router /api/reset-email-or-phone [post]
|
||||||
func (c *ApiController) ResetEmailOrPhone() {
|
func (c *ApiController) ResetEmailOrPhone() {
|
||||||
userId, ok := c.RequireSignedIn()
|
user, ok := c.RequireSignedInUser()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := object.GetUser(userId)
|
|
||||||
if user == nil {
|
|
||||||
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
destType := c.Ctx.Request.Form.Get("type")
|
destType := c.Ctx.Request.Form.Get("type")
|
||||||
dest := c.Ctx.Request.Form.Get("dest")
|
dest := c.Ctx.Request.Form.Get("dest")
|
||||||
code := c.Ctx.Request.Form.Get("code")
|
code := c.Ctx.Request.Form.Get("code")
|
||||||
|
@ -16,6 +16,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@ -100,7 +101,7 @@ func (c *ApiController) WebAuthnSigninBegin() {
|
|||||||
userName := c.Input().Get("name")
|
userName := c.Input().Get("name")
|
||||||
user := object.GetUserByFields(userOwner, userName)
|
user := object.GetUserByFields(userOwner, userName)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
c.ResponseError("Please Giveout Owner and Username.")
|
c.ResponseError(fmt.Sprintf("The user: %s/%s doesn't exist", userOwner, userName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
options, sessionData, err := webauthnObj.BeginLogin(user)
|
options, sessionData, err := webauthnObj.BeginLogin(user)
|
||||||
@ -121,6 +122,7 @@ func (c *ApiController) WebAuthnSigninBegin() {
|
|||||||
// @Success 200 {object} Response "The Response object"
|
// @Success 200 {object} Response "The Response object"
|
||||||
// @router /webauthn/signin/finish [post]
|
// @router /webauthn/signin/finish [post]
|
||||||
func (c *ApiController) WebAuthnSigninFinish() {
|
func (c *ApiController) WebAuthnSigninFinish() {
|
||||||
|
responseType := c.Input().Get("responseType")
|
||||||
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
|
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
|
||||||
sessionObj := c.GetSession("authentication")
|
sessionObj := c.GetSession("authentication")
|
||||||
sessionData, ok := sessionObj.(webauthn.SessionData)
|
sessionData, ok := sessionObj.(webauthn.SessionData)
|
||||||
@ -138,5 +140,11 @@ func (c *ApiController) WebAuthnSigninFinish() {
|
|||||||
}
|
}
|
||||||
c.SetSessionUsername(userId)
|
c.SetSessionUsername(userId)
|
||||||
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
||||||
c.ResponseOk(userId)
|
|
||||||
|
application := object.GetApplicationByUser(user)
|
||||||
|
var form RequestForm
|
||||||
|
form.Type = responseType
|
||||||
|
resp := c.HandleLoggedIn(application, user, &form)
|
||||||
|
c.Data["json"] = resp
|
||||||
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/astaxie/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -76,7 +76,8 @@ func (c *ApiController) UpdateWebhook() {
|
|||||||
var webhook object.Webhook
|
var webhook object.Webhook
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
|
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
|
||||||
@ -94,7 +95,8 @@ func (c *ApiController) AddWebhook() {
|
|||||||
var webhook object.Webhook
|
var webhook object.Webhook
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddWebhook(&webhook))
|
c.Data["json"] = wrapActionResponse(object.AddWebhook(&webhook))
|
||||||
@ -112,7 +114,8 @@ func (c *ApiController) DeleteWebhook() {
|
|||||||
var webhook object.Webhook
|
var webhook object.Webhook
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteWebhook(&webhook))
|
c.Data["json"] = wrapActionResponse(object.DeleteWebhook(&webhook))
|
||||||
|
70
deployment/deploy.go
Normal file
70
deployment/deploy.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package deployment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/storage"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/casdoor/oss"
|
||||||
|
)
|
||||||
|
|
||||||
|
func deployStaticFiles(provider *object.Provider) {
|
||||||
|
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
|
||||||
|
if storageProvider == nil {
|
||||||
|
panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadFolder(storageProvider, "js")
|
||||||
|
uploadFolder(storageProvider, "css")
|
||||||
|
updateHtml(provider.Domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadFolder(storageProvider oss.StorageInterface, folder string) {
|
||||||
|
path := fmt.Sprintf("../web/build/static/%s/", folder)
|
||||||
|
filenames := util.ListFiles(path)
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
if !strings.HasSuffix(filename, folder) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path + filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
objectKey := fmt.Sprintf("static/%s/%s", folder, filename)
|
||||||
|
_, err = storageProvider.Put(objectKey, file)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Uploaded [%s] to [%s]\n", path, objectKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateHtml(domainPath string) {
|
||||||
|
htmlPath := "../web/build/index.html"
|
||||||
|
html := util.ReadStringFromPath(htmlPath)
|
||||||
|
html = strings.Replace(html, "\"/static/", fmt.Sprintf("\"%s", domainPath), -1)
|
||||||
|
util.WriteStringToPath(html, htmlPath)
|
||||||
|
|
||||||
|
fmt.Printf("Updated HTML to [%s]\n", html)
|
||||||
|
}
|
29
deployment/deploy_test.go
Normal file
29
deployment/deploy_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build !skipCi
|
||||||
|
// +build !skipCi
|
||||||
|
|
||||||
|
package deployment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeployStaticFiles(t *testing.T) {
|
||||||
|
provider := object.GetProvider("admin/provider_storage_aliyun_oss")
|
||||||
|
deployStaticFiles(provider)
|
||||||
|
}
|
15
go.mod
15
go.mod
@ -5,39 +5,46 @@ go 1.16
|
|||||||
require (
|
require (
|
||||||
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
|
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
|
||||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
||||||
github.com/astaxie/beego v1.12.3
|
|
||||||
github.com/aws/aws-sdk-go v1.44.4
|
github.com/aws/aws-sdk-go v1.44.4
|
||||||
|
github.com/beego/beego v1.12.11
|
||||||
github.com/beevik/etree v1.1.0
|
github.com/beevik/etree v1.1.0
|
||||||
github.com/casbin/casbin/v2 v2.30.1
|
github.com/casbin/casbin/v2 v2.30.1
|
||||||
github.com/casbin/xorm-adapter/v2 v2.5.1
|
github.com/casbin/xorm-adapter/v3 v3.0.1
|
||||||
github.com/casdoor/go-sms-sender v0.3.0
|
github.com/casdoor/go-sms-sender v0.5.1
|
||||||
github.com/casdoor/goth v1.69.0-FIX2
|
github.com/casdoor/goth v1.69.0-FIX2
|
||||||
github.com/casdoor/oss v1.2.0
|
github.com/casdoor/oss v1.2.0
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
|
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
|
||||||
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
|
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
|
||||||
|
github.com/forestmgy/ldapserver v1.1.0
|
||||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
|
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
|
||||||
github.com/go-ldap/ldap/v3 v3.3.0
|
github.com/go-ldap/ldap/v3 v3.3.0
|
||||||
github.com/go-pay/gopay v1.5.72
|
github.com/go-pay/gopay v1.5.72
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0
|
github.com/golang-jwt/jwt/v4 v4.2.0
|
||||||
|
github.com/google/go-cmp v0.5.8 // indirect
|
||||||
github.com/google/uuid v1.2.0
|
github.com/google/uuid v1.2.0
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||||
github.com/lestrrat-go/jwx v0.9.0
|
github.com/lestrrat-go/jwx v0.9.0
|
||||||
github.com/lib/pq v1.8.0
|
github.com/lib/pq v1.8.0
|
||||||
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/russellhaering/gosaml2 v0.6.0
|
github.com/russellhaering/gosaml2 v0.6.0
|
||||||
github.com/russellhaering/goxmldsig v1.1.1
|
github.com/russellhaering/goxmldsig v1.1.1
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/tealeg/xlsx v1.0.5
|
github.com/tealeg/xlsx v1.0.5
|
||||||
github.com/thanhpk/randstr v1.0.4
|
github.com/thanhpk/randstr v1.0.4
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954
|
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
|
70
go.sum
70
go.sum
@ -74,13 +74,13 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0q
|
|||||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
|
|
||||||
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
|
|
||||||
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
|
||||||
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
|
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
|
||||||
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
|
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
|
||||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||||
|
github.com/beego/beego v1.12.11 h1:MWKcnpavb7iAIS0m6uuEq6pHKkYvGNw/5umIUKqL7jM=
|
||||||
|
github.com/beego/beego v1.12.11/go.mod h1:QURFL1HldOcCZAxnc1cZ7wrplsYR5dKPHFjmk6WkLAs=
|
||||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
||||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||||
@ -96,10 +96,10 @@ github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
|
|||||||
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||||
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
|
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
|
||||||
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
|
||||||
github.com/casbin/xorm-adapter/v2 v2.5.1 h1:BkpIxRHKa0s3bSMx173PpuU7oTs+Zw7XmD0BIta0HGM=
|
github.com/casbin/xorm-adapter/v3 v3.0.1 h1:0l0zkYxo6cNuIdrBZgFxlje1TRvmheYa/zIp+sGPK58=
|
||||||
github.com/casbin/xorm-adapter/v2 v2.5.1/go.mod h1:AeH4dBKHC9/zYxzdPVHhPDzF8LYLqjDdb767CWJoV54=
|
github.com/casbin/xorm-adapter/v3 v3.0.1/go.mod h1:1BL7rHEDXrxO+vQdSo/ZaWKRivXl7YTos67GdMYcd20=
|
||||||
github.com/casdoor/go-sms-sender v0.3.0 h1:c4bWVcKZhO2L3Xu1oy7aeVkCK6HRJkW/b5K1xU9mV60=
|
github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0=
|
||||||
github.com/casdoor/go-sms-sender v0.3.0/go.mod h1:fsZsNnALvFIo+HFcE1U/oCQv4ZT42FdglXKMsEm3WSk=
|
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI=
|
||||||
github.com/casdoor/goth v1.69.0-FIX2 h1:RgfIMkL9kekylgxHHK2ZY8ASAwOGns2HVlaBwLu7Bcs=
|
github.com/casdoor/goth v1.69.0-FIX2 h1:RgfIMkL9kekylgxHHK2ZY8ASAwOGns2HVlaBwLu7Bcs=
|
||||||
github.com/casdoor/goth v1.69.0-FIX2/go.mod h1:Om55nRo8CkeDkPSNBbzXW4G5uI28ZUkSk5S69dPek3s=
|
github.com/casdoor/goth v1.69.0-FIX2/go.mod h1:Om55nRo8CkeDkPSNBbzXW4G5uI28ZUkSk5S69dPek3s=
|
||||||
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
|
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
|
||||||
@ -115,9 +115,9 @@ github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1C
|
|||||||
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
github.com/couchbase/go-couchbase v0.0.0-20201216133707-c04035124b17/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
|
||||||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
github.com/couchbase/gomemcached v0.1.2-0.20201224031647-c432ccf49f32/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=
|
||||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -137,6 +137,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/forestmgy/ldapserver v1.1.0 h1:gvil4nuLhqPEL8SugCkFhRyA0/lIvRdwZSqlrw63ll4=
|
||||||
|
github.com/forestmgy/ldapserver v1.1.0/go.mod h1:1RZ8lox1QSY7rmbjdmy+sYQXY4Lp7SpGzpdE3+j3IyM=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
@ -156,6 +158,8 @@ github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ
|
|||||||
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
|
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
|
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
|
||||||
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
|
github.com/go-pay/gopay v1.5.72/go.mod h1:0qOGIJuFW7PKDOjmecwKyW0mgsVImgwB9yPJj0ilpn8=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
@ -171,6 +175,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
|||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
|
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
@ -186,8 +192,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
|
|||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -219,8 +226,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
@ -297,6 +305,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 h1:wIONC+HMNRqmWBjuMxhatuSzHaljStc4gjDeKycxy0A=
|
||||||
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
|
||||||
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0=
|
||||||
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA=
|
||||||
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro=
|
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro=
|
||||||
@ -331,7 +341,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
|||||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -376,6 +385,8 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
|||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
||||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||||
@ -389,15 +400,17 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
|||||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
|
github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
|
||||||
@ -406,17 +419,26 @@ github.com/tencentcloud/tencentcloud-sdk-go v1.0.154 h1:THBgwGwUQtsw6L53cSSA2wwL
|
|||||||
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
|
github.com/tencentcloud/tencentcloud-sdk-go v1.0.154/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
|
||||||
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
|
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
|
||||||
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||||
|
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||||
|
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||||
|
github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U=
|
||||||
|
github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE=
|
||||||
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
|
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
|
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
|
||||||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
@ -434,6 +456,7 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
@ -469,6 +492,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -503,6 +527,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||||
@ -524,6 +549,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -537,7 +563,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -559,12 +587,17 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -623,10 +656,10 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
@ -739,8 +772,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -121,6 +121,7 @@ func (idp *DingTalkIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
type DingTalkUserResponse struct {
|
type DingTalkUserResponse struct {
|
||||||
Nick string `json:"nick"`
|
Nick string `json:"nick"`
|
||||||
OpenId string `json:"openId"`
|
OpenId string `json:"openId"`
|
||||||
|
UnionId string `json:"unionId"`
|
||||||
AvatarUrl string `json:"avatarUrl"`
|
AvatarUrl string `json:"avatarUrl"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Errmsg string `json:"message"`
|
Errmsg string `json:"message"`
|
||||||
@ -162,6 +163,7 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
|||||||
Id: dtUserInfo.OpenId,
|
Id: dtUserInfo.OpenId,
|
||||||
Username: dtUserInfo.Nick,
|
Username: dtUserInfo.Nick,
|
||||||
DisplayName: dtUserInfo.Nick,
|
DisplayName: dtUserInfo.Nick,
|
||||||
|
UnionId: dtUserInfo.UnionId,
|
||||||
Email: dtUserInfo.Email,
|
Email: dtUserInfo.Email,
|
||||||
AvatarUrl: dtUserInfo.AvatarUrl,
|
AvatarUrl: dtUserInfo.AvatarUrl,
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ func getUser(gothUser goth.User, provider string) *UserInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if provider == "steam" {
|
if provider == "steam" {
|
||||||
user.Username = user.DisplayName
|
user.Username = user.Id
|
||||||
user.Email = ""
|
user.Email = ""
|
||||||
}
|
}
|
||||||
return &user
|
return &user
|
||||||
|
@ -25,6 +25,7 @@ type UserInfo struct {
|
|||||||
Id string
|
Id string
|
||||||
Username string
|
Username string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
|
UnionId string
|
||||||
Email string
|
Email string
|
||||||
AvatarUrl string
|
AvatarUrl string
|
||||||
}
|
}
|
||||||
|
13
main.go
13
main.go
@ -18,11 +18,12 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/beego/beego/logs"
|
||||||
_ "github.com/astaxie/beego/session/redis"
|
_ "github.com/beego/beego/session/redis"
|
||||||
"github.com/casdoor/casdoor/authz"
|
"github.com/casdoor/casdoor/authz"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
"github.com/casdoor/casdoor/controllers"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/proxy"
|
"github.com/casdoor/casdoor/proxy"
|
||||||
"github.com/casdoor/casdoor/routers"
|
"github.com/casdoor/casdoor/routers"
|
||||||
@ -45,7 +46,8 @@ func main() {
|
|||||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||||
|
|
||||||
// beego.DelStaticPath("/static")
|
// beego.DelStaticPath("/static")
|
||||||
beego.SetStaticPath("/static", "web/build/static")
|
// beego.SetStaticPath("/static", "web/build/static")
|
||||||
|
|
||||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||||
beego.SetStaticPath("/swagger", "swagger")
|
beego.SetStaticPath("/swagger", "swagger")
|
||||||
beego.SetStaticPath("/files", "files")
|
beego.SetStaticPath("/files", "files")
|
||||||
@ -75,5 +77,8 @@ func main() {
|
|||||||
port := beego.AppConfig.DefaultInt("httpport", 8000)
|
port := beego.AppConfig.DefaultInt("httpport", 8000)
|
||||||
// logs.SetLevel(logs.LevelInformational)
|
// logs.SetLevel(logs.LevelInformational)
|
||||||
logs.SetLogFuncCall(false)
|
logs.SetLogFuncCall(false)
|
||||||
|
|
||||||
|
go controllers.StartLdapServer()
|
||||||
|
|
||||||
beego.Run(fmt.Sprintf(":%v", port))
|
beego.Run(fmt.Sprintf(":%v", port))
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
|
xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||||
_ "github.com/lib/pq" // db = postgres
|
_ "github.com/lib/pq" // db = postgres
|
||||||
|
"xorm.io/xorm/migrate"
|
||||||
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
|
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
|
||||||
"xorm.io/core"
|
"xorm.io/core"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
@ -40,10 +42,11 @@ func InitConfig() {
|
|||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
|
|
||||||
InitAdapter(true)
|
InitAdapter(true)
|
||||||
|
initMigrations()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitAdapter(createDatabase bool) {
|
func InitAdapter(createDatabase bool) {
|
||||||
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName(), conf.GetConfigString("dbName"))
|
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
|
||||||
if createDatabase {
|
if createDatabase {
|
||||||
adapter.CreateDatabase()
|
adapter.CreateDatabase()
|
||||||
}
|
}
|
||||||
@ -145,6 +148,11 @@ func (a *Adapter) createTable() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(CasbinAdapter))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
err = a.Engine.Sync2(new(Provider))
|
err = a.Engine.Sync2(new(Provider))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -209,6 +217,11 @@ func (a *Adapter) createTable() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(xormadapter.CasbinRule))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
|
||||||
@ -234,3 +247,22 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
|
|||||||
}
|
}
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initMigrations() {
|
||||||
|
migrations := []*migrate.Migration{
|
||||||
|
{
|
||||||
|
ID: "20221015CasbinRule--fill ptype field with p",
|
||||||
|
Migrate: func(tx *xorm.Engine) error {
|
||||||
|
_, err := tx.Cols("ptype").Update(&xormadapter.CasbinRule{
|
||||||
|
Ptype: "p",
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return tx.DropTables(&xormadapter.CasbinRule{})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
m := migrate.New(adapter.Engine, migrate.DefaultOptions, migrations)
|
||||||
|
m.Migrate()
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@ package object
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@ -45,6 +46,7 @@ type Application struct {
|
|||||||
EnablePassword bool `json:"enablePassword"`
|
EnablePassword bool `json:"enablePassword"`
|
||||||
EnableSignUp bool `json:"enableSignUp"`
|
EnableSignUp bool `json:"enableSignUp"`
|
||||||
EnableSigninSession bool `json:"enableSigninSession"`
|
EnableSigninSession bool `json:"enableSigninSession"`
|
||||||
|
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||||
EnableWebAuthn bool `json:"enableWebAuthn"`
|
EnableWebAuthn bool `json:"enableWebAuthn"`
|
||||||
@ -66,6 +68,9 @@ type Application struct {
|
|||||||
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
|
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
|
||||||
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
|
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
|
||||||
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
|
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
|
||||||
|
FormCss string `xorm:"text" json:"formCss"`
|
||||||
|
FormOffset int `json:"formOffset"`
|
||||||
|
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetApplicationCount(owner, field, value string) int {
|
func GetApplicationCount(owner, field, value string) int {
|
||||||
@ -319,7 +324,8 @@ func (application *Application) GetId() string {
|
|||||||
func CheckRedirectUriValid(application *Application, redirectUri string) bool {
|
func CheckRedirectUriValid(application *Application, redirectUri string) bool {
|
||||||
validUri := false
|
validUri := false
|
||||||
for _, tmpUri := range application.RedirectUris {
|
for _, tmpUri := range application.RedirectUris {
|
||||||
if strings.Contains(redirectUri, tmpUri) {
|
tmpUriRegex := regexp.MustCompile(tmpUri)
|
||||||
|
if tmpUriRegex.MatchString(redirectUri) || strings.Contains(redirectUri, tmpUri) {
|
||||||
validUri = true
|
validUri = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -362,3 +368,34 @@ func IsAllowOrigin(origin string) bool {
|
|||||||
|
|
||||||
return allowOrigin
|
return allowOrigin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getApplicationMap(organization string) map[string]*Application {
|
||||||
|
applications := GetApplicationsByOrganizationName("admin", organization)
|
||||||
|
|
||||||
|
applicationMap := make(map[string]*Application)
|
||||||
|
for _, application := range applications {
|
||||||
|
applicationMap[application.Name] = application
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicationMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtendManagedAccountsWithUser(user *User) *User {
|
||||||
|
if user.ManagedAccounts == nil || len(user.ManagedAccounts) == 0 {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationMap := getApplicationMap(user.Owner)
|
||||||
|
|
||||||
|
var managedAccounts []ManagedAccount
|
||||||
|
for _, managedAccount := range user.ManagedAccounts {
|
||||||
|
application := applicationMap[managedAccount.Application]
|
||||||
|
if application != nil {
|
||||||
|
managedAccount.SigninUrl = application.SigninUrl
|
||||||
|
managedAccounts = append(managedAccounts, managedAccount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.ManagedAccounts = managedAccounts
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
@ -73,6 +73,10 @@ func (application *Application) IsSignupItemRequired(itemName string) bool {
|
|||||||
return signupItem.Required
|
return signupItem.Required
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (si *SignupItem) isSignupItemPrompted() bool {
|
||||||
|
return si.Visible && si.Prompted
|
||||||
|
}
|
||||||
|
|
||||||
func (application *Application) GetSignupItemRule(itemName string) string {
|
func (application *Application) GetSignupItemRule(itemName string) string {
|
||||||
signupItem := application.getSignupItem(itemName)
|
signupItem := application.getSignupItem(itemName)
|
||||||
if signupItem == nil {
|
if signupItem == nil {
|
||||||
@ -92,6 +96,16 @@ func (application *Application) getAllPromptedProviderItems() []*ProviderItem {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (application *Application) getAllPromptedSignupItems() []*SignupItem {
|
||||||
|
res := []*SignupItem{}
|
||||||
|
for _, signupItem := range application.SignupItems {
|
||||||
|
if signupItem.isSignupItemPrompted() {
|
||||||
|
res = append(res, signupItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func (application *Application) isAffiliationPrompted() bool {
|
func (application *Application) isAffiliationPrompted() bool {
|
||||||
signupItem := application.getSignupItem("Affiliation")
|
signupItem := application.getSignupItem("Affiliation")
|
||||||
if signupItem == nil {
|
if signupItem == nil {
|
||||||
@ -107,5 +121,10 @@ func (application *Application) HasPromptPage() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signupItems := application.getAllPromptedSignupItems()
|
||||||
|
if len(signupItems) != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return application.isAffiliationPrompted()
|
return application.isAffiliationPrompted()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func downloadFile(url string) (*bytes.Buffer, error) {
|
|||||||
return fileBuffer, nil
|
return fileBuffer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPermanentAvatarUrl(organization string, username string, url string) string {
|
func getPermanentAvatarUrl(organization string, username string, url string, upload bool) string {
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -62,6 +62,14 @@ func getPermanentAvatarUrl(organization string, username string, url string) str
|
|||||||
fullFilePath := fmt.Sprintf("/avatar/%s/%s.png", organization, username)
|
fullFilePath := fmt.Sprintf("/avatar/%s/%s.png", organization, username)
|
||||||
uploadedFileUrl, _ := getUploadFileUrl(defaultStorageProvider, fullFilePath, false)
|
uploadedFileUrl, _ := getUploadFileUrl(defaultStorageProvider, fullFilePath, false)
|
||||||
|
|
||||||
|
if upload {
|
||||||
|
DownloadAndUpload(url, fullFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uploadedFileUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadAndUpload(url string, fullFilePath string) {
|
||||||
fileBuffer, err := downloadFile(url)
|
fileBuffer, err := downloadFile(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -71,6 +79,4 @@ func getPermanentAvatarUrl(organization string, username string, url string) str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return uploadedFileUrl
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ func TestSyncPermanentAvatars(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
|
||||||
updateUserColumn("permanent_avatar", user)
|
updateUserColumn("permanent_avatar", user)
|
||||||
fmt.Printf("[%d/%d]: Update user: [%s]'s permanent avatar: %s\n", i, len(users), user.GetId(), user.PermanentAvatar)
|
fmt.Printf("[%d/%d]: Update user: [%s]'s permanent avatar: %s\n", i, len(users), user.GetId(), user.PermanentAvatar)
|
||||||
}
|
}
|
||||||
|
217
object/casbin_adapter.go
Normal file
217
object/casbin_adapter.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/casbin/casbin/v2/model"
|
||||||
|
xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
|
||||||
|
"xorm.io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CasbinAdapter struct {
|
||||||
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
|
|
||||||
|
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||||
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
|
Model string `xorm:"varchar(100)" json:"model"`
|
||||||
|
|
||||||
|
Host string `xorm:"varchar(100)" json:"host"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
|
Password string `xorm:"varchar(100)" json:"password"`
|
||||||
|
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
||||||
|
Database string `xorm:"varchar(100)" json:"database"`
|
||||||
|
Table string `xorm:"varchar(100)" json:"table"`
|
||||||
|
IsEnabled bool `json:"isEnabled"`
|
||||||
|
|
||||||
|
Adapter *xormadapter.Adapter `xorm:"-" json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCasbinAdapterCount(owner, field, value string) int {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&CasbinAdapter{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCasbinAdapters(owner string) []*CasbinAdapter {
|
||||||
|
adapters := []*CasbinAdapter{}
|
||||||
|
err := adapter.Engine.Where("owner = ?", owner).Find(&adapters)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationCasbinAdapters(owner string, page, limit int, field, value, sort, order string) []*CasbinAdapter {
|
||||||
|
session := GetSession(owner, page, limit, field, value, sort, order)
|
||||||
|
adapters := []*CasbinAdapter{}
|
||||||
|
err := session.Find(&adapters)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCasbinAdapter(owner, name string) *CasbinAdapter {
|
||||||
|
if owner == "" || name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
casbinAdapter := CasbinAdapter{Owner: owner, Name: name}
|
||||||
|
existed, err := adapter.Engine.Get(&casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
return &casbinAdapter
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCasbinAdapter(id string) *CasbinAdapter {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getCasbinAdapter(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateCasbinAdapter(id string, casbinAdapter *CasbinAdapter) bool {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if getCasbinAdapter(owner, name) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
session := adapter.Engine.ID(core.PK{owner, name}).AllCols()
|
||||||
|
if casbinAdapter.Password == "***" {
|
||||||
|
session.Omit("password")
|
||||||
|
}
|
||||||
|
affected, err := session.Update(casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCasbinAdapter(casbinAdapter *CasbinAdapter) bool {
|
||||||
|
affected, err := adapter.Engine.Insert(casbinAdapter)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteCasbinAdapter(casbinAdapter *CasbinAdapter) bool {
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{casbinAdapter.Owner, casbinAdapter.Name}).Delete(&CasbinAdapter{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (casbinAdapter *CasbinAdapter) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", casbinAdapter.Owner, casbinAdapter.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (casbinAdapter *CasbinAdapter) getTable() string {
|
||||||
|
if casbinAdapter.DatabaseType == "mssql" {
|
||||||
|
return fmt.Sprintf("[%s]", casbinAdapter.Table)
|
||||||
|
} else {
|
||||||
|
return casbinAdapter.Table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeReturn(policy []string, i int) string {
|
||||||
|
if len(policy) > i {
|
||||||
|
return policy[i]
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func matrixToCasbinRules(pType string, policies [][]string) []*xormadapter.CasbinRule {
|
||||||
|
res := []*xormadapter.CasbinRule{}
|
||||||
|
|
||||||
|
for _, policy := range policies {
|
||||||
|
line := xormadapter.CasbinRule{
|
||||||
|
Ptype: pType,
|
||||||
|
V0: safeReturn(policy, 0),
|
||||||
|
V1: safeReturn(policy, 1),
|
||||||
|
V2: safeReturn(policy, 2),
|
||||||
|
V3: safeReturn(policy, 3),
|
||||||
|
V4: safeReturn(policy, 4),
|
||||||
|
V5: safeReturn(policy, 5),
|
||||||
|
}
|
||||||
|
res = append(res, &line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func SyncPolicies(casbinAdapter *CasbinAdapter) []*xormadapter.CasbinRule {
|
||||||
|
// init Adapter
|
||||||
|
if casbinAdapter.Adapter == nil {
|
||||||
|
var dataSourceName string
|
||||||
|
if casbinAdapter.DatabaseType == "mssql" {
|
||||||
|
dataSourceName = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
|
||||||
|
} else if casbinAdapter.DatabaseType == "postgres" {
|
||||||
|
dataSourceName = fmt.Sprintf("user=%s password=%s host=%s port=%d sslmode=disable dbname=%s", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port, casbinAdapter.Database)
|
||||||
|
} else {
|
||||||
|
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", casbinAdapter.User, casbinAdapter.Password, casbinAdapter.Host, casbinAdapter.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isCloudIntranet {
|
||||||
|
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
||||||
|
}
|
||||||
|
|
||||||
|
casbinAdapter.Adapter, _ = xormadapter.NewAdapterByEngineWithTableName(NewAdapter(casbinAdapter.DatabaseType, dataSourceName, casbinAdapter.Database).Engine, casbinAdapter.getTable(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// init Model
|
||||||
|
modelObj := getModel(casbinAdapter.Owner, casbinAdapter.Model)
|
||||||
|
m, err := model.NewModelFromString(modelObj.ModelText)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// init Enforcer
|
||||||
|
enforcer, err := casbin.NewEnforcer(m, casbinAdapter.Adapter)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policies := matrixToCasbinRules("p", enforcer.GetPolicy())
|
||||||
|
if strings.Contains(modelObj.ModelText, "[role_definition]") {
|
||||||
|
policies = append(policies, matrixToCasbinRules("g", enforcer.GetGroupingPolicy())...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return policies
|
||||||
|
}
|
@ -59,13 +59,18 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
|||||||
if reWhiteSpace.MatchString(username) {
|
if reWhiteSpace.MatchString(username) {
|
||||||
return "username cannot contain white spaces"
|
return "username cannot contain white spaces"
|
||||||
}
|
}
|
||||||
|
msg := CheckUsername(username)
|
||||||
|
if msg != "" {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
if HasUserByField(organization.Name, "name", username) {
|
if HasUserByField(organization.Name, "name", username) {
|
||||||
return "username already exists"
|
return "username already exists"
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "email", username) {
|
if HasUserByField(organization.Name, "email", email) {
|
||||||
return "email already exists"
|
return "email already exists"
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "phone", username) {
|
if HasUserByField(organization.Name, "phone", phone) {
|
||||||
return "phone already exists"
|
return "phone already exists"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,6 +307,10 @@ func CheckAccessPermission(userId string, application *Application) (bool, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isHit {
|
if isHit {
|
||||||
|
containsAsterisk := ContainsAsterisk(userId, permission.Users)
|
||||||
|
if containsAsterisk {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
enforcer := getEnforcer(permission)
|
enforcer := getEnforcer(permission)
|
||||||
allowed, err = enforcer.Enforce(userId, application.Name, "read")
|
allowed, err = enforcer.Enforce(userId, application.Name, "read")
|
||||||
break
|
break
|
||||||
@ -309,3 +318,24 @@ func CheckAccessPermission(userId string, application *Application) (bool, error
|
|||||||
}
|
}
|
||||||
return allowed, err
|
return allowed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckUsername(username string) string {
|
||||||
|
if username == "" {
|
||||||
|
return "Empty username."
|
||||||
|
} else if len(username) > 39 {
|
||||||
|
return "Username is too long (maximum is 39 characters)."
|
||||||
|
}
|
||||||
|
|
||||||
|
exclude, _ := regexp.Compile("^[\u0021-\u007E]+$")
|
||||||
|
if !exclude.MatchString(username) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/58726546/github-username-convention-using-regex
|
||||||
|
re, _ := regexp.Compile("^[a-zA-Z0-9]+((?:-[a-zA-Z0-9]+)|(?:_[a-zA-Z0-9]+))*$")
|
||||||
|
if !re.MatchString(username) {
|
||||||
|
return "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline."
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -16,10 +16,28 @@
|
|||||||
|
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import "github.com/go-gomail/gomail"
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
|
"github.com/go-gomail/gomail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDialer(provider *Provider) *gomail.Dialer {
|
||||||
|
dialer := &gomail.Dialer{}
|
||||||
|
if provider.Type == "SUBMAIL" {
|
||||||
|
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.AppId, provider.ClientSecret)
|
||||||
|
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
} else {
|
||||||
|
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
dialer.SSL = !provider.DisableSsl
|
||||||
|
|
||||||
|
return dialer
|
||||||
|
}
|
||||||
|
|
||||||
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
|
func SendEmail(provider *Provider, title string, content string, dest string, sender string) error {
|
||||||
dialer := gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
|
dialer := getDialer(provider)
|
||||||
|
|
||||||
message := gomail.NewMessage()
|
message := gomail.NewMessage()
|
||||||
message.SetAddressHeader("From", provider.ClientId, sender)
|
message.SetAddressHeader("From", provider.ClientId, sender)
|
||||||
@ -32,8 +50,7 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
|
|||||||
|
|
||||||
// DailSmtpServer Dail Smtp server
|
// DailSmtpServer Dail Smtp server
|
||||||
func DailSmtpServer(provider *Provider) error {
|
func DailSmtpServer(provider *Provider) error {
|
||||||
dialer := gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
|
dialer := getDialer(provider)
|
||||||
dialer.SSL = !provider.DisableSsl
|
|
||||||
|
|
||||||
sender, err := dialer.Dial()
|
sender, err := dialer.Dial()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,14 +19,17 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/duo-labs/webauthn/webauthn"
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitDb() {
|
func InitDb() {
|
||||||
|
MigratePermissionRule()
|
||||||
|
|
||||||
existed := initBuiltInOrganization()
|
existed := initBuiltInOrganization()
|
||||||
if !existed {
|
if !existed {
|
||||||
|
initBuiltInModel()
|
||||||
initBuiltInPermission()
|
initBuiltInPermission()
|
||||||
initBuiltInProvider()
|
initBuiltInProvider()
|
||||||
initBuiltInUser()
|
initBuiltInUser()
|
||||||
@ -38,8 +41,6 @@ func InitDb() {
|
|||||||
initWebAuthn()
|
initWebAuthn()
|
||||||
}
|
}
|
||||||
|
|
||||||
var staticBaseUrl = beego.AppConfig.String("staticBaseUrl")
|
|
||||||
|
|
||||||
func initBuiltInOrganization() bool {
|
func initBuiltInOrganization() bool {
|
||||||
organization := getOrganization("admin", "built-in")
|
organization := getOrganization("admin", "built-in")
|
||||||
if organization != nil {
|
if organization != nil {
|
||||||
@ -52,10 +53,10 @@ func initBuiltInOrganization() bool {
|
|||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Built-in Organization",
|
DisplayName: "Built-in Organization",
|
||||||
WebsiteUrl: "https://example.com",
|
WebsiteUrl: "https://example.com",
|
||||||
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", staticBaseUrl),
|
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
|
||||||
PasswordType: "plain",
|
PasswordType: "plain",
|
||||||
PhonePrefix: "86",
|
PhonePrefix: "86",
|
||||||
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", staticBaseUrl),
|
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
AccountItems: []*AccountItem{
|
AccountItems: []*AccountItem{
|
||||||
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||||
@ -84,6 +85,7 @@ func initBuiltInOrganization() bool {
|
|||||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
|
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
AddOrganization(organization)
|
AddOrganization(organization)
|
||||||
@ -104,7 +106,7 @@ func initBuiltInUser() {
|
|||||||
Type: "normal-user",
|
Type: "normal-user",
|
||||||
Password: "123",
|
Password: "123",
|
||||||
DisplayName: "Admin",
|
DisplayName: "Admin",
|
||||||
Avatar: fmt.Sprintf("%s/img/casbin.svg", staticBaseUrl),
|
Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||||
Email: "admin@example.com",
|
Email: "admin@example.com",
|
||||||
Phone: "12345678910",
|
Phone: "12345678910",
|
||||||
Address: []string{},
|
Address: []string{},
|
||||||
@ -134,7 +136,7 @@ func initBuiltInApplication() {
|
|||||||
Name: "app-built-in",
|
Name: "app-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Casdoor",
|
DisplayName: "Casdoor",
|
||||||
Logo: fmt.Sprintf("%s/img/casdoor-logo_1185x256.png", staticBaseUrl),
|
Logo: fmt.Sprintf("%s/img/casdoor-logo_1185x256.png", conf.GetConfigString("staticBaseUrl")),
|
||||||
HomepageUrl: "https://casdoor.org",
|
HomepageUrl: "https://casdoor.org",
|
||||||
Organization: "built-in",
|
Organization: "built-in",
|
||||||
Cert: "cert-built-in",
|
Cert: "cert-built-in",
|
||||||
@ -155,6 +157,7 @@ func initBuiltInApplication() {
|
|||||||
},
|
},
|
||||||
RedirectUris: []string{},
|
RedirectUris: []string{},
|
||||||
ExpireInHours: 168,
|
ExpireInHours: 168,
|
||||||
|
FormOffset: 8,
|
||||||
}
|
}
|
||||||
AddApplication(application)
|
AddApplication(application)
|
||||||
}
|
}
|
||||||
@ -238,6 +241,33 @@ func initWebAuthn() {
|
|||||||
gob.Register(webauthn.SessionData{})
|
gob.Register(webauthn.SessionData{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initBuiltInModel() {
|
||||||
|
model := GetModel("built-in/model-built-in")
|
||||||
|
if model != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
model = &Model{
|
||||||
|
Owner: "built-in",
|
||||||
|
Name: "model-built-in",
|
||||||
|
CreatedTime: util.GetCurrentTime(),
|
||||||
|
DisplayName: "Built-in Model",
|
||||||
|
IsEnabled: true,
|
||||||
|
ModelText: `[request_definition]
|
||||||
|
r = sub, obj, act
|
||||||
|
|
||||||
|
[policy_definition]
|
||||||
|
p = sub, obj, act
|
||||||
|
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow))
|
||||||
|
|
||||||
|
[matchers]
|
||||||
|
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`,
|
||||||
|
}
|
||||||
|
AddModel(model)
|
||||||
|
}
|
||||||
|
|
||||||
func initBuiltInPermission() {
|
func initBuiltInPermission() {
|
||||||
permission := GetPermission("built-in/permission-built-in")
|
permission := GetPermission("built-in/permission-built-in")
|
||||||
if permission != nil {
|
if permission != nil {
|
||||||
@ -249,9 +279,10 @@ func initBuiltInPermission() {
|
|||||||
Name: "permission-built-in",
|
Name: "permission-built-in",
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: "Built-in Permission",
|
DisplayName: "Built-in Permission",
|
||||||
Users: []string{"built-in/admin"},
|
Users: []string{"built-in/*"},
|
||||||
Roles: []string{},
|
Roles: []string{},
|
||||||
Domains: []string{},
|
Domains: []string{},
|
||||||
|
Model: "model-built-in",
|
||||||
ResourceType: "Application",
|
ResourceType: "Application",
|
||||||
Resources: []string{"app-built-in"},
|
Resources: []string{"app-built-in"},
|
||||||
Actions: []string{"Read", "Write", "Admin"},
|
Actions: []string{"Read", "Write", "Admin"},
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
"github.com/thanhpk/randstr"
|
"github.com/thanhpk/randstr"
|
||||||
@ -409,6 +409,7 @@ func SyncLdapUsers(owner string, users []LdapRespUser, ldapId string) (*[]LdapRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found && !AddUser(&User{
|
if !found && !AddUser(&User{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Name: buildLdapUserName(user.Uid, user.UidNumber),
|
Name: buildLdapUserName(user.Uid, user.UidNumber),
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/beego/beego/logs"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
74
object/ldapserver.go
Normal file
74
object/ldapserver.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/forestmgy/ldapserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetNameAndOrgFromDN(DN string) (string, string, string) {
|
||||||
|
DNValue := strings.Split(DN, ",")
|
||||||
|
if len(DNValue) == 1 || strings.ToLower(DNValue[0])[0] != 'c' || strings.ToLower(DNValue[1])[0] != 'o' {
|
||||||
|
return "", "", "please use correct Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
|
||||||
|
}
|
||||||
|
return DNValue[0][3:], DNValue[1][3:], ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserNameAndOrgFromBaseDnAndFilter(baseDN, filter string) (string, string, int) {
|
||||||
|
if !strings.Contains(baseDN, "ou=") || !strings.Contains(filter, "cn=") {
|
||||||
|
return "", "", ldapserver.LDAPResultInvalidDNSyntax
|
||||||
|
}
|
||||||
|
name := getUserNameFromFilter(filter)
|
||||||
|
_, org, _ := GetNameAndOrgFromDN(fmt.Sprintf("cn=%s,", name) + baseDN)
|
||||||
|
errCode := ldapserver.LDAPResultSuccess
|
||||||
|
return name, org, errCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserNameFromFilter(filter string) string {
|
||||||
|
nameIndex := strings.Index(filter, "cn=")
|
||||||
|
var name string
|
||||||
|
for i := nameIndex + 3; filter[i] != ')'; i++ {
|
||||||
|
name = name + string(filter[i])
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFilteredUsers(m *ldapserver.Message, name, org string) ([]*User, int) {
|
||||||
|
var filteredUsers []*User
|
||||||
|
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
|
||||||
|
if m.Client.OrgName == "built-in" && org == "*" {
|
||||||
|
filteredUsers = GetGlobalUsers()
|
||||||
|
return filteredUsers, ldapserver.LDAPResultSuccess
|
||||||
|
} else if m.Client.OrgName == "built-in" || org == m.Client.OrgName {
|
||||||
|
filteredUsers = GetUsers(org)
|
||||||
|
return filteredUsers, ldapserver.LDAPResultSuccess
|
||||||
|
} else {
|
||||||
|
return nil, ldapserver.LDAPResultInsufficientAccessRights
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasPermission, err := CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true)
|
||||||
|
if !hasPermission {
|
||||||
|
log.Printf("ErrMsg = %v", err.Error())
|
||||||
|
return nil, ldapserver.LDAPResultInsufficientAccessRights
|
||||||
|
}
|
||||||
|
user := getUser(org, name)
|
||||||
|
filteredUsers = append(filteredUsers, user)
|
||||||
|
return filteredUsers, ldapserver.LDAPResultSuccess
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ package object
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casbin/casbin/v2/model"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"xorm.io/core"
|
"xorm.io/core"
|
||||||
)
|
)
|
||||||
@ -85,13 +86,19 @@ func GetModel(id string) *Model {
|
|||||||
return getModel(owner, name)
|
return getModel(owner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateModel(id string, model *Model) bool {
|
func UpdateModel(id string, modelObj *Model) bool {
|
||||||
owner, name := util.GetOwnerAndNameFromId(id)
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
if getModel(owner, name) == nil {
|
if getModel(owner, name) == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(model)
|
// check model grammar
|
||||||
|
_, err := model.NewModelFromString(modelObj.ModelText)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(modelObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,11 @@ type OidcDiscovery struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getOriginFromHost(host string) (string, string) {
|
func getOriginFromHost(host string) (string, string) {
|
||||||
|
origin := conf.GetConfigString("origin")
|
||||||
|
if origin != "" {
|
||||||
|
return origin, origin
|
||||||
|
}
|
||||||
|
|
||||||
protocol := "https://"
|
protocol := "https://"
|
||||||
if strings.HasPrefix(host, "localhost") {
|
if strings.HasPrefix(host, "localhost") {
|
||||||
protocol = "http://"
|
protocol = "http://"
|
||||||
@ -58,12 +63,6 @@ func getOriginFromHost(host string) (string, string) {
|
|||||||
func GetOidcDiscovery(host string) OidcDiscovery {
|
func GetOidcDiscovery(host string) OidcDiscovery {
|
||||||
originFrontend, originBackend := getOriginFromHost(host)
|
originFrontend, originBackend := getOriginFromHost(host)
|
||||||
|
|
||||||
origin := conf.GetConfigString("origin")
|
|
||||||
if origin != "" {
|
|
||||||
originFrontend = origin
|
|
||||||
originBackend = origin
|
|
||||||
}
|
|
||||||
|
|
||||||
// Examples:
|
// Examples:
|
||||||
// https://login.okta.com/.well-known/openid-configuration
|
// https://login.okta.com/.well-known/openid-configuration
|
||||||
// https://auth0.auth0.com/.well-known/openid-configuration
|
// https://auth0.auth0.com/.well-known/openid-configuration
|
||||||
|
@ -41,12 +41,13 @@ type Organization struct {
|
|||||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||||
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"`
|
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"`
|
||||||
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
|
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
|
||||||
|
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
|
||||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||||
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
|
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
|
||||||
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
||||||
IsProfilePublic bool `json:"isProfilePublic"`
|
IsProfilePublic bool `json:"isProfilePublic"`
|
||||||
|
|
||||||
AccountItems []*AccountItem `xorm:"varchar(2000)" json:"accountItems"`
|
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOrganizationCount(owner, field, value string) int {
|
func GetOrganizationCount(owner, field, value string) int {
|
||||||
@ -216,3 +217,37 @@ func CheckAccountItemModifyRule(accountItem *AccountItem, user *User) (bool, str
|
|||||||
}
|
}
|
||||||
return true, ""
|
return true, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDefaultApplication(id string) (*Application, error) {
|
||||||
|
organization := GetOrganization(id)
|
||||||
|
if organization == nil {
|
||||||
|
return nil, fmt.Errorf("The organization: %s does not exist", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if organization.DefaultApplication != "" {
|
||||||
|
return getApplication("admin", organization.DefaultApplication), fmt.Errorf("The default application: %s does not exist", organization.DefaultApplication)
|
||||||
|
}
|
||||||
|
|
||||||
|
applications := []*Application{}
|
||||||
|
err := adapter.Engine.Asc("created_time").Find(&applications, &Application{Organization: organization.Name})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(applications) == 0 {
|
||||||
|
return nil, fmt.Errorf("The application does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultApplication := applications[0]
|
||||||
|
for _, application := range applications {
|
||||||
|
if application.EnableSignUp {
|
||||||
|
defaultApplication = application
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extendApplicationWithProviders(defaultApplication)
|
||||||
|
extendApplicationWithOrg(defaultApplication)
|
||||||
|
|
||||||
|
return defaultApplication, nil
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"xorm.io/core"
|
"xorm.io/core"
|
||||||
@ -207,3 +208,44 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
|
|||||||
|
|
||||||
return permissions
|
return permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MigratePermissionRule() {
|
||||||
|
models := []*Model{}
|
||||||
|
err := adapter.Engine.Find(&models, &Model{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isHit := false
|
||||||
|
for _, model := range models {
|
||||||
|
if strings.Contains(model.ModelText, "permission") {
|
||||||
|
// update model table
|
||||||
|
model.ModelText = strings.Replace(model.ModelText, "permission,", "", -1)
|
||||||
|
UpdateModel(model.GetId(), model)
|
||||||
|
isHit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isHit {
|
||||||
|
// update permission_rule table
|
||||||
|
sql := "UPDATE `permission_rule`SET V0 = V1, V1 = V2, V2 = V3, V3 = V4, V4 = V5 WHERE V0 IN (SELECT CONCAT(owner, '/', name) AS permission_id FROM `permission`)"
|
||||||
|
_, err = adapter.Engine.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContainsAsterisk(userId string, users []string) bool {
|
||||||
|
containsAsterisk := false
|
||||||
|
group, _ := util.GetOwnerAndNameFromId(userId)
|
||||||
|
for _, user := range users {
|
||||||
|
permissionGroup, permissionUserName := util.GetOwnerAndNameFromId(user)
|
||||||
|
if permissionGroup == group && permissionUserName == "*" {
|
||||||
|
containsAsterisk = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return containsAsterisk
|
||||||
|
}
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/casbin/casbin/v2"
|
"github.com/casbin/casbin/v2"
|
||||||
"github.com/casbin/casbin/v2/model"
|
"github.com/casbin/casbin/v2/model"
|
||||||
xormadapter "github.com/casbin/xorm-adapter/v2"
|
xormadapter "github.com/casbin/xorm-adapter/v3"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ func getEnforcer(permission *Permission) *casbin.Enforcer {
|
|||||||
tableName = permission.Adapter
|
tableName = permission.Adapter
|
||||||
}
|
}
|
||||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), tableName, tableNamePrefix, true)
|
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName()+conf.GetConfigString("dbName"), tableName, tableNamePrefix, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ type Provider struct {
|
|||||||
DisableSsl bool `json:"disableSsl"`
|
DisableSsl bool `json:"disableSsl"`
|
||||||
Title string `xorm:"varchar(100)" json:"title"`
|
Title string `xorm:"varchar(100)" json:"title"`
|
||||||
Content string `xorm:"varchar(1000)" json:"content"`
|
Content string `xorm:"varchar(1000)" json:"content"`
|
||||||
|
Receiver string `xorm:"varchar(100)" json:"receiver"`
|
||||||
|
|
||||||
RegionId string `xorm:"varchar(100)" json:"regionId"`
|
RegionId string `xorm:"varchar(100)" json:"regionId"`
|
||||||
SignName string `xorm:"varchar(100)" json:"signName"`
|
SignName string `xorm:"varchar(100)" json:"signName"`
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -101,9 +101,9 @@ func AddRecord(record *Record) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRecordCount(field, value string) int {
|
func GetRecordCount(field, value string, filterRecord *Record) int {
|
||||||
session := GetSession("", -1, -1, field, value, "", "")
|
session := GetSession("", -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Record{})
|
count, err := session.Count(filterRecord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -121,10 +121,10 @@ func GetRecords() []*Record {
|
|||||||
return records
|
return records
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder string) []*Record {
|
func GetPaginationRecords(offset, limit int, field, value, sortField, sortOrder string, filterRecord *Record) []*Record {
|
||||||
records := []*Record{}
|
records := []*Record{}
|
||||||
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&records)
|
err := session.Find(&records, filterRecord)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/RobotsAndPencils/go-saml"
|
"github.com/RobotsAndPencils/go-saml"
|
||||||
"github.com/astaxie/beego"
|
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
dsig "github.com/russellhaering/goxmldsig"
|
dsig "github.com/russellhaering/goxmldsig"
|
||||||
@ -176,16 +175,12 @@ type Attribute struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, error) {
|
func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, error) {
|
||||||
//_, originBackend := getOriginFromHost(host)
|
|
||||||
cert := getCertByApplication(application)
|
cert := getCertByApplication(application)
|
||||||
block, _ := pem.Decode([]byte(cert.Certificate))
|
block, _ := pem.Decode([]byte(cert.Certificate))
|
||||||
certificate := base64.StdEncoding.EncodeToString(block.Bytes)
|
certificate := base64.StdEncoding.EncodeToString(block.Bytes)
|
||||||
|
|
||||||
origin := beego.AppConfig.String("origin")
|
|
||||||
originFrontend, originBackend := getOriginFromHost(host)
|
originFrontend, originBackend := getOriginFromHost(host)
|
||||||
if origin != "" {
|
|
||||||
originBackend = origin
|
|
||||||
}
|
|
||||||
d := IdpEntityDescriptor{
|
d := IdpEntityDescriptor{
|
||||||
XMLName: xml.Name{
|
XMLName: xml.Name{
|
||||||
Local: "md:EntityDescriptor",
|
Local: "md:EntityDescriptor",
|
||||||
|
@ -70,10 +70,12 @@ func GenerateSamlLoginUrl(id, relayState string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildSp(provider *Provider, samlResponse string) (*saml2.SAMLServiceProvider, error) {
|
func buildSp(provider *Provider, samlResponse string) (*saml2.SAMLServiceProvider, error) {
|
||||||
|
origin := conf.GetConfigString("origin")
|
||||||
|
|
||||||
certStore := dsig.MemoryX509CertificateStore{
|
certStore := dsig.MemoryX509CertificateStore{
|
||||||
Roots: []*x509.Certificate{},
|
Roots: []*x509.Certificate{},
|
||||||
}
|
}
|
||||||
origin := conf.GetConfigString("origin")
|
|
||||||
certEncodedData := ""
|
certEncodedData := ""
|
||||||
if samlResponse != "" {
|
if samlResponse != "" {
|
||||||
certEncodedData = parseSamlResponse(samlResponse, provider.Type)
|
certEncodedData = parseSamlResponse(samlResponse, provider.Type)
|
||||||
|
@ -103,6 +103,11 @@ func uploadFile(provider *Provider, fullFilePath string, fileBuffer *bytes.Buffe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UploadFileSafe(provider *Provider, fullFilePath string, fileBuffer *bytes.Buffer) (string, string, error) {
|
func UploadFileSafe(provider *Provider, fullFilePath string, fileBuffer *bytes.Buffer) (string, string, error) {
|
||||||
|
// check fullFilePath is there security issue
|
||||||
|
if strings.Contains(fullFilePath, "..") {
|
||||||
|
return "", "", fmt.Errorf("the fullFilePath: %s is not allowed", fullFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
var fileUrl string
|
var fileUrl string
|
||||||
var objectKey string
|
var objectKey string
|
||||||
var err error
|
var err error
|
||||||
@ -122,6 +127,11 @@ func UploadFileSafe(provider *Provider, fullFilePath string, fileBuffer *bytes.B
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteFile(provider *Provider, objectKey string) error {
|
func DeleteFile(provider *Provider, objectKey string) error {
|
||||||
|
// check fullFilePath is there security issue
|
||||||
|
if strings.Contains(objectKey, "..") {
|
||||||
|
return fmt.Errorf("the objectKey: %s is not allowed", objectKey)
|
||||||
|
}
|
||||||
|
|
||||||
endpoint := getProviderEndpoint(provider)
|
endpoint := getProviderEndpoint(provider)
|
||||||
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, endpoint)
|
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, endpoint)
|
||||||
if storageProvider == nil {
|
if storageProvider == nil {
|
||||||
|
@ -120,7 +120,7 @@ func (syncer *Syncer) updateUserForOriginalFields(user *User) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
columns := syncer.getCasdoorColumns()
|
columns := syncer.getCasdoorColumns()
|
||||||
|
@ -287,6 +287,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExtendUserWithRolesAndPermissions(user)
|
||||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, nonce, scope, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -421,6 +422,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExtendUserWithRolesAndPermissions(user)
|
||||||
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
newAccessToken, newRefreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &TokenError{
|
return &TokenError{
|
||||||
@ -571,6 +573,7 @@ func GetPasswordToken(application *Application, username string, password string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExtendUserWithRolesAndPermissions(user)
|
||||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &TokenError{
|
return nil, &TokenError{
|
||||||
@ -640,6 +643,7 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
|
|||||||
// GetTokenByUser
|
// GetTokenByUser
|
||||||
// Implicit flow
|
// Implicit flow
|
||||||
func GetTokenByUser(application *Application, user *User, scope string, host string) (*Token, error) {
|
func GetTokenByUser(application *Application, user *User, scope string, host string) (*Token, error) {
|
||||||
|
ExtendUserWithRolesAndPermissions(user)
|
||||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", scope, host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -699,7 +703,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
|||||||
}
|
}
|
||||||
// Add new user
|
// Add new user
|
||||||
var name string
|
var name string
|
||||||
if username != "" {
|
if CheckUsername(username) == "" {
|
||||||
name = username
|
name = username
|
||||||
} else {
|
} else {
|
||||||
name = fmt.Sprintf("wechat-%s", openId)
|
name = fmt.Sprintf("wechat-%s", openId)
|
||||||
@ -726,6 +730,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
|||||||
AddUser(user)
|
AddUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExtendUserWithRolesAndPermissions(user)
|
||||||
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", host)
|
accessToken, refreshToken, tokenName, err := generateJwtToken(application, user, "", "", host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &TokenError{
|
return nil, &TokenError{
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
)
|
)
|
||||||
@ -67,11 +66,7 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
|
|||||||
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
||||||
|
|
||||||
user.Password = ""
|
user.Password = ""
|
||||||
origin := conf.GetConfigString("origin")
|
|
||||||
_, originBackend := getOriginFromHost(host)
|
_, originBackend := getOriginFromHost(host)
|
||||||
if origin != "" {
|
|
||||||
originBackend = origin
|
|
||||||
}
|
|
||||||
|
|
||||||
name := util.GenerateId()
|
name := util.GenerateId()
|
||||||
jti := fmt.Sprintf("%s/%s", application.Owner, name)
|
jti := fmt.Sprintf("%s/%s", application.Owner, name)
|
||||||
|
@ -114,6 +114,8 @@ type User struct {
|
|||||||
|
|
||||||
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
|
||||||
SigninWrongTimes int `json:"signinWrongTimes"`
|
SigninWrongTimes int `json:"signinWrongTimes"`
|
||||||
|
|
||||||
|
ManagedAccounts []ManagedAccount `xorm:"managedAccounts blob" json:"managedAccounts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Userinfo struct {
|
type Userinfo struct {
|
||||||
@ -128,6 +130,13 @@ type Userinfo struct {
|
|||||||
Phone string `json:"phone,omitempty"`
|
Phone string `json:"phone,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ManagedAccount struct {
|
||||||
|
Application string `xorm:"varchar(100)" json:"application"`
|
||||||
|
Username string `xorm:"varchar(100)" json:"username"`
|
||||||
|
Password string `xorm:"varchar(100)" json:"password"`
|
||||||
|
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
func GetGlobalUserCount(field, value string) int {
|
func GetGlobalUserCount(field, value string) int {
|
||||||
session := GetSession("", -1, -1, field, value, "", "")
|
session := GetSession("", -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&User{})
|
count, err := session.Count(&User{})
|
||||||
@ -334,6 +343,12 @@ func GetMaskedUser(user *User) *User {
|
|||||||
if user.Password != "" {
|
if user.Password != "" {
|
||||||
user.Password = "***"
|
user.Password = "***"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.ManagedAccounts != nil {
|
||||||
|
for _, manageAccount := range user.ManagedAccounts {
|
||||||
|
manageAccount.Password = "***"
|
||||||
|
}
|
||||||
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,14 +386,14 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
|||||||
user.UpdateUserHash()
|
user.UpdateUserHash()
|
||||||
|
|
||||||
if user.Avatar != oldUser.Avatar && user.Avatar != "" && user.PermanentAvatar != "*" {
|
if user.Avatar != oldUser.Avatar && user.Avatar != "" && user.PermanentAvatar != "*" {
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(columns) == 0 {
|
if len(columns) == 0 {
|
||||||
columns = []string{
|
columns = []string{
|
||||||
"owner", "display_name", "avatar",
|
"owner", "display_name", "avatar",
|
||||||
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials",
|
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||||
"signin_wrong_times", "last_signin_wrong_time",
|
"signin_wrong_times", "last_signin_wrong_time",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,7 +419,7 @@ func UpdateUserForAllFields(id string, user *User) bool {
|
|||||||
user.UpdateUserHash()
|
user.UpdateUserHash()
|
||||||
|
|
||||||
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
if user.Avatar != oldUser.Avatar && user.Avatar != "" {
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(user)
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(user)
|
||||||
@ -434,7 +449,7 @@ func AddUser(user *User) bool {
|
|||||||
user.UpdateUserHash()
|
user.UpdateUserHash()
|
||||||
user.PreHash = user.Hash
|
user.PreHash = user.Hash
|
||||||
|
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, false)
|
||||||
|
|
||||||
user.Ranking = GetUserCount(user.Owner, "", "") + 1
|
user.Ranking = GetUserCount(user.Owner, "", "") + 1
|
||||||
|
|
||||||
@ -459,7 +474,7 @@ func AddUsers(users []*User) bool {
|
|||||||
user.UpdateUserHash()
|
user.UpdateUserHash()
|
||||||
user.PreHash = user.Hash
|
user.PreHash = user.Hash
|
||||||
|
|
||||||
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar)
|
user.PermanentAvatar = getPermanentAvatarUrl(user.Owner, user.Name, user.Avatar, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.Insert(users)
|
affected, err := adapter.Engine.Insert(users)
|
||||||
@ -473,7 +488,7 @@ func AddUsers(users []*User) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddUsersInBatch(users []*User) bool {
|
func AddUsersInBatch(users []*User) bool {
|
||||||
batchSize := 1000
|
batchSize := conf.GetConfigBatchSize()
|
||||||
|
|
||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
return false
|
return false
|
||||||
@ -507,16 +522,8 @@ func DeleteUser(user *User) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserInfo(userId string, scope string, aud string, host string) (*Userinfo, error) {
|
func GetUserInfo(user *User, scope string, aud string, host string) *Userinfo {
|
||||||
user := GetUser(userId)
|
|
||||||
if user == nil {
|
|
||||||
return nil, fmt.Errorf("the user: %s doesn't exist", userId)
|
|
||||||
}
|
|
||||||
origin := conf.GetConfigString("origin")
|
|
||||||
_, originBackend := getOriginFromHost(host)
|
_, originBackend := getOriginFromHost(host)
|
||||||
if origin != "" {
|
|
||||||
originBackend = origin
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := Userinfo{
|
resp := Userinfo{
|
||||||
Sub: user.Id,
|
Sub: user.Id,
|
||||||
@ -537,7 +544,7 @@ func GetUserInfo(userId string, scope string, aud string, host string) (*Userinf
|
|||||||
if strings.Contains(scope, "phone") {
|
if strings.Contains(scope, "phone") {
|
||||||
resp.Phone = user.Phone
|
resp.Phone = user.Phone
|
||||||
}
|
}
|
||||||
return &resp, nil
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
func LinkUserAccount(user *User, field string, value string) bool {
|
func LinkUserAccount(user *User, field string, value string) bool {
|
||||||
@ -551,3 +558,12 @@ func (user *User) GetId() string {
|
|||||||
func isUserIdGlobalAdmin(userId string) bool {
|
func isUserIdGlobalAdmin(userId string) bool {
|
||||||
return strings.HasPrefix(userId, "built-in/")
|
return strings.HasPrefix(userId, "built-in/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExtendUserWithRolesAndPermissions(user *User) {
|
||||||
|
if user == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Roles = GetRolesByUser(user.GetId())
|
||||||
|
user.Permissions = GetPermissionsByUser(user.GetId())
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@ package object
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@ -108,3 +109,24 @@ func TestGetUserByField(t *testing.T) {
|
|||||||
t.Log("no user found")
|
t.Log("no user found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetEmailsForUsers(t *testing.T) {
|
||||||
|
InitConfig()
|
||||||
|
|
||||||
|
emailMap := map[string]int{}
|
||||||
|
emails := []string{}
|
||||||
|
users := GetUsers("built-in")
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Email == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := emailMap[user.Email]; !ok {
|
||||||
|
emailMap[user.Email] = 1
|
||||||
|
emails = append(emails, user.Email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text := strings.Join(emails, "\n")
|
||||||
|
println(text)
|
||||||
|
}
|
||||||
|
@ -80,7 +80,7 @@ func SetUserField(user *User, field string, value string) bool {
|
|||||||
value = user.Password
|
value = user.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(map[string]interface{}{field: value})
|
affected, err := adapter.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(map[string]interface{}{strings.ToLower(field): value})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -137,6 +137,12 @@ func SetUserOAuthProperties(organization *Organization, user *User, providerType
|
|||||||
user.Email = userInfo.Email
|
user.Email = userInfo.Email
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if userInfo.UnionId != "" {
|
||||||
|
propertyName := fmt.Sprintf("oauth_%s_unionId", providerType)
|
||||||
|
setUserProperty(user, propertyName, userInfo.UnionId)
|
||||||
|
}
|
||||||
|
|
||||||
if userInfo.AvatarUrl != "" {
|
if userInfo.AvatarUrl != "" {
|
||||||
propertyName := fmt.Sprintf("oauth_%s_avatarUrl", providerType)
|
propertyName := fmt.Sprintf("oauth_%s_avatarUrl", providerType)
|
||||||
setUserProperty(user, propertyName, userInfo.AvatarUrl)
|
setUserProperty(user, propertyName, userInfo.AvatarUrl)
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/duo-labs/webauthn/protocol"
|
"github.com/duo-labs/webauthn/protocol"
|
||||||
"github.com/duo-labs/webauthn/webauthn"
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
)
|
)
|
||||||
@ -27,20 +27,17 @@ import (
|
|||||||
func GetWebAuthnObject(host string) *webauthn.WebAuthn {
|
func GetWebAuthnObject(host string) *webauthn.WebAuthn {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
origin := beego.AppConfig.String("origin")
|
_, originBackend := getOriginFromHost(host)
|
||||||
if origin == "" {
|
|
||||||
_, origin = getOriginFromHost(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
localUrl, err := url.Parse(origin)
|
localUrl, err := url.Parse(originBackend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("error when parsing origin:" + err.Error())
|
panic("error when parsing origin:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
webAuthn, err := webauthn.New(&webauthn.Config{
|
webAuthn, err := webauthn.New(&webauthn.Config{
|
||||||
RPDisplayName: beego.AppConfig.String("appname"), // Display Name for your site
|
RPDisplayName: conf.GetConfigString("appname"), // Display Name for your site
|
||||||
RPID: strings.Split(localUrl.Host, ":")[0], // Generally the domain name for your site, it's ok because splits cannot return empty array
|
RPID: strings.Split(localUrl.Host, ":")[0], // Generally the domain name for your site, it's ok because splits cannot return empty array
|
||||||
RPOrigin: origin, // The origin URL for WebAuthn requests
|
RPOrigin: originBackend, // The origin URL for WebAuthn requests
|
||||||
// RPIcon: "https://duo.com/logo.png", // Optional icon URL for your site
|
// RPIcon: "https://duo.com/logo.png", // Optional icon URL for your site
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -47,15 +47,15 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
|
|||||||
|
|
||||||
sender := organization.DisplayName
|
sender := organization.DisplayName
|
||||||
title := provider.Title
|
title := provider.Title
|
||||||
code := getRandomCode(5)
|
code := getRandomCode(6)
|
||||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||||
content := fmt.Sprintf(provider.Content, code)
|
content := fmt.Sprintf(provider.Content, code)
|
||||||
|
|
||||||
if err := AddToVerificationRecord(user, provider, remoteAddr, provider.Category, dest, code); err != nil {
|
if err := SendEmail(provider, title, content, dest, sender); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return SendEmail(provider, title, content, dest, sender)
|
return AddToVerificationRecord(user, provider, remoteAddr, provider.Category, dest, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendVerificationCodeToPhone(organization *Organization, user *User, provider *Provider, remoteAddr string, dest string) error {
|
func SendVerificationCodeToPhone(organization *Organization, user *User, provider *Provider, remoteAddr string, dest string) error {
|
||||||
@ -63,12 +63,12 @@ func SendVerificationCodeToPhone(organization *Organization, user *User, provide
|
|||||||
return errors.New("please set a SMS provider first")
|
return errors.New("please set a SMS provider first")
|
||||||
}
|
}
|
||||||
|
|
||||||
code := getRandomCode(5)
|
code := getRandomCode(6)
|
||||||
if err := AddToVerificationRecord(user, provider, remoteAddr, provider.Category, dest, code); err != nil {
|
if err := SendSms(provider, code, dest); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return SendSms(provider, code, dest)
|
return AddToVerificationRecord(user, provider, remoteAddr, provider.Category, dest, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordType, dest, code string) error {
|
func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordType, dest, code string) error {
|
||||||
@ -159,7 +159,7 @@ func DisableVerificationCode(dest string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Casnode/object/validateCode.go line 116
|
// From Casnode/object/validateCode.go line 116
|
||||||
var stdNums = []byte("0123456789")
|
var stdNums = []byte("0123456789")
|
||||||
|
|
||||||
func getRandomCode(length int) string {
|
func getRandomCode(length int) string {
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/authz"
|
"github.com/casdoor/casdoor/authz"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@ -63,11 +63,16 @@ func getObject(ctx *context.Context) (string, string) {
|
|||||||
if method == http.MethodGet {
|
if method == http.MethodGet {
|
||||||
// query == "?id=built-in/admin"
|
// query == "?id=built-in/admin"
|
||||||
id := ctx.Input.Query("id")
|
id := ctx.Input.Query("id")
|
||||||
if id == "" {
|
if id != "" {
|
||||||
return "", ""
|
return util.GetOwnerAndNameFromId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.GetOwnerAndNameFromId(id)
|
owner := ctx.Input.Query("owner")
|
||||||
|
if owner != "" {
|
||||||
|
return owner, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ""
|
||||||
} else {
|
} else {
|
||||||
body := ctx.Input.RequestBody
|
body := ctx.Input.RequestBody
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ package routers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +17,7 @@ package routers
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +17,7 @@ package routers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
package routers
|
package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego"
|
"github.com/beego/beego"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/controllers"
|
"github.com/casdoor/casdoor/controllers"
|
||||||
)
|
)
|
||||||
@ -60,6 +60,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/update-organization", &controllers.ApiController{}, "POST:UpdateOrganization")
|
beego.Router("/api/update-organization", &controllers.ApiController{}, "POST:UpdateOrganization")
|
||||||
beego.Router("/api/add-organization", &controllers.ApiController{}, "POST:AddOrganization")
|
beego.Router("/api/add-organization", &controllers.ApiController{}, "POST:AddOrganization")
|
||||||
beego.Router("/api/delete-organization", &controllers.ApiController{}, "POST:DeleteOrganization")
|
beego.Router("/api/delete-organization", &controllers.ApiController{}, "POST:DeleteOrganization")
|
||||||
|
beego.Router("/api/get-default-application", &controllers.ApiController{}, "GET:GetDefaultApplication")
|
||||||
|
|
||||||
beego.Router("/api/get-global-users", &controllers.ApiController{}, "GET:GetGlobalUsers")
|
beego.Router("/api/get-global-users", &controllers.ApiController{}, "GET:GetGlobalUsers")
|
||||||
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
|
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
|
||||||
@ -96,6 +97,13 @@ func initAPI() {
|
|||||||
beego.Router("/api/add-model", &controllers.ApiController{}, "POST:AddModel")
|
beego.Router("/api/add-model", &controllers.ApiController{}, "POST:AddModel")
|
||||||
beego.Router("/api/delete-model", &controllers.ApiController{}, "POST:DeleteModel")
|
beego.Router("/api/delete-model", &controllers.ApiController{}, "POST:DeleteModel")
|
||||||
|
|
||||||
|
beego.Router("/api/get-adapters", &controllers.ApiController{}, "GET:GetCasbinAdapters")
|
||||||
|
beego.Router("/api/get-adapter", &controllers.ApiController{}, "GET:GetCasbinAdapter")
|
||||||
|
beego.Router("/api/update-adapter", &controllers.ApiController{}, "POST:UpdateCasbinAdapter")
|
||||||
|
beego.Router("/api/add-adapter", &controllers.ApiController{}, "POST:AddCasbinAdapter")
|
||||||
|
beego.Router("/api/delete-adapter", &controllers.ApiController{}, "POST:DeleteCasbinAdapter")
|
||||||
|
beego.Router("/api/sync-policies", &controllers.ApiController{}, "GET:SyncPolicies")
|
||||||
|
|
||||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||||
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "POST:GetEmailAndPhone")
|
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "POST:GetEmailAndPhone")
|
||||||
@ -147,6 +155,7 @@ func initAPI() {
|
|||||||
|
|
||||||
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")
|
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")
|
||||||
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
|
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
|
||||||
|
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
|
||||||
|
|
||||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||||
@ -202,4 +211,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish")
|
beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish")
|
||||||
beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin")
|
beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin")
|
||||||
beego.Router("/api/webauthn/signin/finish", &controllers.ApiController{}, "Post:WebAuthnSigninFinish")
|
beego.Router("/api/webauthn/signin/finish", &controllers.ApiController{}, "Post:WebAuthnSigninFinish")
|
||||||
|
|
||||||
|
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
||||||
|
beego.Router("/api/get-release", &controllers.ApiController{}, "GET:GitRepoVersion")
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,19 @@ package routers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
oldStaticBaseUrl = "https://cdn.casbin.org"
|
||||||
|
newStaticBaseUrl = conf.GetConfigString("staticBaseUrl")
|
||||||
|
)
|
||||||
|
|
||||||
func StaticFilter(ctx *context.Context) {
|
func StaticFilter(ctx *context.Context) {
|
||||||
urlPath := ctx.Request.URL.Path
|
urlPath := ctx.Request.URL.Path
|
||||||
if strings.HasPrefix(urlPath, "/api/") || strings.HasPrefix(urlPath, "/.well-known/") {
|
if strings.HasPrefix(urlPath, "/api/") || strings.HasPrefix(urlPath, "/.well-known/") {
|
||||||
@ -38,9 +45,35 @@ func StaticFilter(ctx *context.Context) {
|
|||||||
path += urlPath
|
path += urlPath
|
||||||
}
|
}
|
||||||
|
|
||||||
if util.FileExist(path) {
|
if !util.FileExist(path) {
|
||||||
|
path = "web/build/index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldStaticBaseUrl == newStaticBaseUrl {
|
||||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
|
http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
|
||||||
} else {
|
} else {
|
||||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, "web/build/index.html")
|
serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path, oldStaticBaseUrl, newStaticBaseUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, old string, new string) {
|
||||||
|
f, err := os.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
d, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldContent := util.ReadStringFromPath(name)
|
||||||
|
newContent := strings.ReplaceAll(oldContent, old, new)
|
||||||
|
|
||||||
|
http.ServeContent(w, r, d.Name(), d.ModTime(), strings.NewReader(newContent))
|
||||||
|
_, err = w.Write([]byte(newContent))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
storage/minio_s3.go
Normal file
36
storage/minio_s3.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
awss3 "github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
"github.com/casdoor/oss"
|
||||||
|
"github.com/casdoor/oss/s3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMinIOS3StorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
|
||||||
|
sp := s3.New(&s3.Config{
|
||||||
|
AccessID: clientId,
|
||||||
|
AccessKey: clientSecret,
|
||||||
|
Region: region,
|
||||||
|
Bucket: bucket,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
S3Endpoint: endpoint,
|
||||||
|
ACL: awss3.BucketCannedACLPublicRead,
|
||||||
|
S3ForcePathStyle: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return sp
|
||||||
|
}
|
@ -22,6 +22,8 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
|
|||||||
return NewLocalFileSystemStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewLocalFileSystemStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
case "AWS S3":
|
case "AWS S3":
|
||||||
return NewAwsS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewAwsS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
|
case "MinIO":
|
||||||
|
return NewMinIOS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
case "Aliyun OSS":
|
case "Aliyun OSS":
|
||||||
return NewAliyunOssStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
return NewAliyunOssStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||||
case "Tencent Cloud COS":
|
case "Tencent Cloud COS":
|
||||||
|
@ -19,8 +19,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/context"
|
"github.com/beego/beego/context"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/beego/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetIPInfo(clientIP string) string {
|
func GetIPInfo(clientIP string) string {
|
||||||
|
18
util/path.go
18
util/path.go
@ -16,6 +16,7 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -43,6 +44,23 @@ func EnsureFileFolderExists(path string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListFiles(path string) []string {
|
||||||
|
res := []string{}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
if !f.IsDir() {
|
||||||
|
res = append(res, f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func RemoveExt(filename string) string {
|
func RemoveExt(filename string) string {
|
||||||
return filename[:len(filename)-len(filepath.Ext(filename))]
|
return filename[:len(filename)-len(filepath.Ext(filename))]
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ package util
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/beego/beego/logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SafeGoroutine(fn func()) {
|
func SafeGoroutine(fn func()) {
|
78
util/system.go
Normal file
78
util/system.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// get cpu usage
|
||||||
|
func GetCpuUsage() ([]float64, error) {
|
||||||
|
usage, err := cpu.Percent(time.Second, true)
|
||||||
|
return usage, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDate, version string
|
||||||
|
|
||||||
|
// get memory usage
|
||||||
|
func GetMemoryUsage() (uint64, uint64, error) {
|
||||||
|
virtualMem, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var m runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&m)
|
||||||
|
|
||||||
|
return m.TotalAlloc, virtualMem.Total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get github repo release version
|
||||||
|
func GetGitRepoVersion() (string, error) {
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfos, err := ioutil.ReadDir(pwd + "/.git/refs/heads")
|
||||||
|
for _, v := range fileInfos {
|
||||||
|
if v.Name() == "master" {
|
||||||
|
if v.ModTime().String() == fileDate {
|
||||||
|
return version, nil
|
||||||
|
} else {
|
||||||
|
fileDate = v.ModTime().String()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(pwd + "/.git/refs/heads/master")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to full length
|
||||||
|
temp := string(content)
|
||||||
|
version = strings.ReplaceAll(temp, "\n", "")
|
||||||
|
|
||||||
|
return version, nil
|
||||||
|
}
|
33
util/sysytem_test.go
Normal file
33
util/sysytem_test.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetCpuUsage(t *testing.T) {
|
||||||
|
usage, err := GetCpuUsage()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
t.Log(usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetMemoryUsage(t *testing.T) {
|
||||||
|
used, total, err := GetMemoryUsage()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
t.Log(used, total)
|
||||||
|
}
|
@ -4,12 +4,18 @@
|
|||||||
"es6": true,
|
"es6": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"parser": "babel-eslint",
|
"parser": "@babel/eslint-parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 12,
|
"ecmaVersion": 12,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true
|
"jsx": true
|
||||||
|
},
|
||||||
|
"requireConfigFile": false,
|
||||||
|
"babelOptions": {
|
||||||
|
"babelrc": false,
|
||||||
|
"configFile": false,
|
||||||
|
"presets": ["@babel/preset-react"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -91,6 +97,7 @@
|
|||||||
"react/jsx-key": "error",
|
"react/jsx-key": "error",
|
||||||
"no-console": "error",
|
"no-console": "error",
|
||||||
"eqeqeq": "error",
|
"eqeqeq": "error",
|
||||||
|
"keyword-spacing": "error",
|
||||||
|
|
||||||
"react/prop-types": "off",
|
"react/prop-types": "off",
|
||||||
"react/display-name": "off",
|
"react/display-name": "off",
|
||||||
|
6
web/.stylelintrc.json
Normal file
6
web/.stylelintrc.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"stylelint-config-standard",
|
||||||
|
"stylelint-config-recommended-less"
|
||||||
|
]
|
||||||
|
}
|
17
web/babel.config.json
Normal file
17
web/babel.config.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"targets": {
|
||||||
|
"edge": "17",
|
||||||
|
"firefox": "60",
|
||||||
|
"chrome": "67",
|
||||||
|
"safari": "11.1"
|
||||||
|
},
|
||||||
|
"useBuiltIns": "usage",
|
||||||
|
"corejs": "3.6.5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
@ -43,7 +43,7 @@ module.exports = {
|
|||||||
options: {
|
options: {
|
||||||
lessLoaderOptions: {
|
lessLoaderOptions: {
|
||||||
lessOptions: {
|
lessOptions: {
|
||||||
modifyVars: {"@primary-color": "rgb(45,120,213)"},
|
modifyVars: {"@primary-color": "rgb(89,54,213)", "@border-radius-base": "5px"},
|
||||||
javascriptEnabled: true,
|
javascriptEnabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3,35 +3,35 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.6.2",
|
"@ant-design/icons": "^4.7.0",
|
||||||
"@craco/craco": "^6.1.1",
|
"@craco/craco": "^6.4.5",
|
||||||
"@crowdin/cli": "^3.6.4",
|
"@crowdin/cli": "^3.7.10",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
"@testing-library/user-event": "^7.1.2",
|
"@testing-library/user-event": "^7.1.2",
|
||||||
"antd": "^4.15.5",
|
"antd": "^4.22.8",
|
||||||
"codemirror": "^5.61.1",
|
"codemirror": "^5.61.1",
|
||||||
"copy-to-clipboard": "^3.3.1",
|
"copy-to-clipboard": "^3.3.1",
|
||||||
"core-js": "^3.21.1",
|
"core-js": "^3.25.0",
|
||||||
"craco-less": "^1.17.1",
|
"craco-less": "^2.0.0",
|
||||||
"eslint-plugin-unused-imports": "^2.0.0",
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18n-iso-countries": "^7.0.0",
|
"i18n-iso-countries": "^7.0.0",
|
||||||
"i18next": "^19.8.9",
|
"i18next": "^19.8.9",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"qs": "^6.10.2",
|
"qs": "^6.10.2",
|
||||||
"react": "^17.0.2",
|
"react": "^18.2.0",
|
||||||
"react-app-polyfill": "^3.0.0",
|
"react-app-polyfill": "^3.0.0",
|
||||||
"react-codemirror2": "^7.2.1",
|
"react-codemirror2": "^7.2.1",
|
||||||
"react-cropper": "^2.1.7",
|
"react-cropper": "^2.1.7",
|
||||||
"react-device-detect": "^1.14.0",
|
"react-device-detect": "^2.2.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.2.0",
|
||||||
"react-github-corner": "^2.5.0",
|
"react-github-corner": "^2.5.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-highlight-words": "^0.17.0",
|
"react-highlight-words": "^0.18.0",
|
||||||
"react-i18next": "^11.8.7",
|
"react-i18next": "^11.8.7",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.3.3",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "5.0.1",
|
||||||
"react-social-login-buttons": "^3.4.0"
|
"react-social-login-buttons": "^3.4.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -41,7 +41,8 @@
|
|||||||
"eject": "craco eject",
|
"eject": "craco eject",
|
||||||
"crowdin:sync": "crowdin upload && crowdin download",
|
"crowdin:sync": "crowdin upload && crowdin download",
|
||||||
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
|
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
|
||||||
"fix": "eslint --fix ."
|
"fix": "eslint --fix src/**/*.{js,jsx,ts,tsx}",
|
||||||
|
"lint:css": "stylelint src/**/*.{css,less} --fix"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
@ -61,15 +62,24 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.18.13",
|
||||||
|
"@babel/eslint-parser": "^7.18.9",
|
||||||
|
"@babel/preset-react": "^7.18.6",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^7.11.0",
|
"eslint": "8.22.0",
|
||||||
"eslint-plugin-react": "^7.30.1",
|
"eslint-plugin-react": "^7.31.1",
|
||||||
"husky": "^4.3.8",
|
"husky": "^4.3.8",
|
||||||
"lint-staged": "^13.0.3"
|
"lint-staged": "^13.0.3",
|
||||||
|
"stylelint": "^14.11.0",
|
||||||
|
"stylelint-config-recommended-less": "^1.0.4",
|
||||||
|
"stylelint-config-standard": "^28.0.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"src/**/*.{js,jsx,css,sass,ts,tsx}": [
|
"src/**/*.{css,less}": [
|
||||||
"yarn fix"
|
"stylelint --fix"
|
||||||
|
],
|
||||||
|
"src/**/*.{js,jsx,ts,tsx}": [
|
||||||
|
"eslint --fix"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
name="description"
|
name="description"
|
||||||
content="Casdoor - An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS"
|
content="Casdoor - An Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML and CAS"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="https://cdn.casdoor.com/static/favicon.png" />
|
<link rel="apple-touch-icon" href="https://cdn.casbin.org/img/favicon.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
|
@ -95,6 +95,7 @@ class AccountTable extends React.Component {
|
|||||||
{name: "Is forbidden", displayName: i18next.t("user:Is forbidden")},
|
{name: "Is forbidden", displayName: i18next.t("user:Is forbidden")},
|
||||||
{name: "Is deleted", displayName: i18next.t("user:Is deleted")},
|
{name: "Is deleted", displayName: i18next.t("user:Is deleted")},
|
||||||
{name: "WebAuthn credentials", displayName: i18next.t("user:WebAuthn credentials")},
|
{name: "WebAuthn credentials", displayName: i18next.t("user:WebAuthn credentials")},
|
||||||
|
{name: "Managed accounts", displayName: i18next.t("user:Managed accounts")},
|
||||||
];
|
];
|
||||||
|
|
||||||
const getItemDisplayName = (text) => {
|
const getItemDisplayName = (text) => {
|
||||||
|
412
web/src/AdapterEditPage.js
Normal file
412
web/src/AdapterEditPage.js
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch, Table, Tooltip} from "antd";
|
||||||
|
import * as AdapterBackend from "./backend/AdapterBackend";
|
||||||
|
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import * as ModelBackend from "./backend/ModelBackend";
|
||||||
|
import {EditOutlined, MinusOutlined} from "@ant-design/icons";
|
||||||
|
require("codemirror/theme/material-darker.css");
|
||||||
|
require("codemirror/mode/javascript/javascript");
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
|
class AdapterEditPage extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||||
|
adapterName: props.match.params.adapterName,
|
||||||
|
adapter: null,
|
||||||
|
organizations: [],
|
||||||
|
models: [],
|
||||||
|
policyLists: [],
|
||||||
|
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
UNSAFE_componentWillMount() {
|
||||||
|
this.getAdapter();
|
||||||
|
this.getOrganizations();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAdapter() {
|
||||||
|
AdapterBackend.getAdapter(this.state.organizationName, this.state.adapterName)
|
||||||
|
.then((adapter) => {
|
||||||
|
this.setState({
|
||||||
|
adapter: adapter,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.getModels(adapter.owner);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrganizations() {
|
||||||
|
OrganizationBackend.getOrganizations(this.state.organizationName)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
organizations: (res.msg === undefined) ? res : [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getModels(organizationName) {
|
||||||
|
ModelBackend.getModels(organizationName)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
models: res,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parseAdapterField(key, value) {
|
||||||
|
if (["port"].includes(key)) {
|
||||||
|
value = Setting.myParseInt(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAdapterField(key, value) {
|
||||||
|
value = this.parseAdapterField(key, value);
|
||||||
|
|
||||||
|
const adapter = this.state.adapter;
|
||||||
|
adapter[key] = value;
|
||||||
|
this.setState({
|
||||||
|
adapter: adapter,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
synPolicies() {
|
||||||
|
this.setState({loading: true});
|
||||||
|
AdapterBackend.syncPolicies(this.state.adapter.owner, this.state.adapter.name)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({loading: false, policyLists: res});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.setState({loading: false});
|
||||||
|
Setting.showMessage("error", `Adapter failed to get policies: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(table) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: "Rule Type",
|
||||||
|
dataIndex: "PType",
|
||||||
|
key: "PType",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V0",
|
||||||
|
dataIndex: "V0",
|
||||||
|
key: "V0",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V1",
|
||||||
|
dataIndex: "V1",
|
||||||
|
key: "V1",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V2",
|
||||||
|
dataIndex: "V2",
|
||||||
|
key: "V2",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V3",
|
||||||
|
dataIndex: "V3",
|
||||||
|
key: "V3",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V4",
|
||||||
|
dataIndex: "V4",
|
||||||
|
key: "V4",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "V5",
|
||||||
|
dataIndex: "V5",
|
||||||
|
key: "V5",
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Option",
|
||||||
|
key: "option",
|
||||||
|
width: "100px",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Tooltip placement="topLeft" title="Edit">
|
||||||
|
<Button style={{marginRight: "0.5rem"}} icon={<EditOutlined />} size="small" />
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip placement="topLeft" title="Delete">
|
||||||
|
<Button icon={<MinusOutlined />} size="small" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table
|
||||||
|
pagination={{
|
||||||
|
defaultPageSize: 10,
|
||||||
|
}}
|
||||||
|
columns={columns} dataSource={table} rowKey="name" size="middle" bordered
|
||||||
|
loading={this.state.loading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAdapter() {
|
||||||
|
return (
|
||||||
|
<Card size="small" title={
|
||||||
|
<div>
|
||||||
|
{this.state.mode === "add" ? i18next.t("adapter:New Adapter") : i18next.t("adapter:Edit Adapter")}
|
||||||
|
<Button onClick={() => this.submitAdapterEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||||
|
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitAdapterEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||||
|
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteAdapter()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||||
|
</div>
|
||||||
|
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||||
|
<Row style={{marginTop: "10px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.adapter.organization} onChange={(value => {this.updateadapterField("organization", value);})}>
|
||||||
|
{
|
||||||
|
this.state.organizations.map((organization, index) => <Option key={index} value={organization.name}>{organization.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.name} onChange={e => {
|
||||||
|
this.updateAdapterField("name", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("provider:Type"), i18next.t("provider:Type - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.adapter.type} onChange={(value => {
|
||||||
|
this.updateAdapterField("type", value);
|
||||||
|
const adapter = this.state.adapter;
|
||||||
|
// adapter["tableColumns"] = Setting.getAdapterTableColumns(this.state.adapter);
|
||||||
|
this.setState({
|
||||||
|
adapter: adapter,
|
||||||
|
});
|
||||||
|
})}>
|
||||||
|
{
|
||||||
|
["Database"]
|
||||||
|
.map((item, index) => <Option key={index} value={item}>{item}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.host} onChange={e => {
|
||||||
|
this.updateAdapterField("host", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<InputNumber value={this.state.adapter.port} onChange={value => {
|
||||||
|
this.updateAdapterField("port", value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:User"), i18next.t("general:User - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.user} onChange={e => {
|
||||||
|
this.updateAdapterField("user", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.password} onChange={e => {
|
||||||
|
this.updateAdapterField("password", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:Database type"), i18next.t("syncer:Database type - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.adapter.databaseType} onChange={(value => {this.updateAdapterField("databaseType", value);})}>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
{id: "mysql", name: "MySQL"},
|
||||||
|
{id: "postgres", name: "PostgreSQL"},
|
||||||
|
{id: "mssql", name: "SQL Server"},
|
||||||
|
{id: "oracle", name: "Oracle"},
|
||||||
|
{id: "sqlite3", name: "Sqlite 3"},
|
||||||
|
].map((databaseType, index) => <Option key={index} value={databaseType.id}>{databaseType.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:Database"), i18next.t("syncer:Database - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.database} onChange={e => {
|
||||||
|
this.updateAdapterField("database", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:Table"), i18next.t("syncer:Table - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.adapter.table}
|
||||||
|
disabled={this.state.adapter.type === "Keycloak"} onChange={e => {
|
||||||
|
this.updateAdapterField("table", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Model"), i18next.t("general:Model - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.adapter.model} onChange={(model => {
|
||||||
|
this.updateAdapterField("model", model);
|
||||||
|
})}>
|
||||||
|
{
|
||||||
|
this.state.models.map((model, index) => <Option key={index} value={model.name}>{model.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("adapter:Policies"), i18next.t("adapter:Policies - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<Button type="primary" onClick={() => {this.synPolicies();}}>
|
||||||
|
{i18next.t("adapter:Sync")}
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
{
|
||||||
|
this.renderTable(this.state.policyLists)
|
||||||
|
}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Is enabled"), i18next.t("general:Is enabled - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={1} >
|
||||||
|
<Switch checked={this.state.adapter.isEnabled} onChange={checked => {
|
||||||
|
this.updateAdapterField("isEnabled", checked);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitAdapterEdit(willExist) {
|
||||||
|
const adapter = Setting.deepCopy(this.state.adapter);
|
||||||
|
AdapterBackend.updateAdapter(this.state.adapter.owner, this.state.adapterName, adapter)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.msg === "") {
|
||||||
|
Setting.showMessage("success", "Successfully saved");
|
||||||
|
this.setState({
|
||||||
|
adapterName: this.state.adapter.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (willExist) {
|
||||||
|
this.props.history.push("/adapters");
|
||||||
|
} else {
|
||||||
|
this.props.history.push(`/adapters/${this.state.adapter.name}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", res.msg);
|
||||||
|
this.updateAdapterField("name", this.state.adapterName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `Failed to connect to server: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteAdapter() {
|
||||||
|
AdapterBackend.deleteAdapter(this.state.adapter)
|
||||||
|
.then(() => {
|
||||||
|
this.props.history.push("/adapters");
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `adapter failed to delete: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
this.state.adapter !== null ? this.renderAdapter() : null
|
||||||
|
}
|
||||||
|
<div style={{marginTop: "20px", marginLeft: "40px"}}>
|
||||||
|
<Button size="large" onClick={() => this.submitAdapterEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||||
|
<Button style={{marginLeft: "20px"}} type="primary" size="large" onClick={() => this.submitAdapterEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||||
|
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} size="large" onClick={() => this.deleteAdapter()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdapterEditPage;
|
261
web/src/AdapterListPage.js
Normal file
261
web/src/AdapterListPage.js
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {Button, Popconfirm, Switch, Table} from "antd";
|
||||||
|
import moment from "moment";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import * as AdapterBackend from "./backend/AdapterBackend";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import BaseListPage from "./BaseListPage";
|
||||||
|
|
||||||
|
class AdapterListPage extends BaseListPage {
|
||||||
|
newAdapter() {
|
||||||
|
const randomName = Setting.getRandomName();
|
||||||
|
return {
|
||||||
|
owner: "built-in",
|
||||||
|
name: `adapter_${randomName}`,
|
||||||
|
createdTime: moment().format(),
|
||||||
|
organization: "built-in",
|
||||||
|
type: "Database",
|
||||||
|
host: "localhost",
|
||||||
|
port: 3306,
|
||||||
|
user: "root",
|
||||||
|
password: "123456",
|
||||||
|
databaseType: "mysql",
|
||||||
|
database: "dbName",
|
||||||
|
table: "tableName",
|
||||||
|
isEnabled: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addAdapter() {
|
||||||
|
const newAdapter = this.newAdapter();
|
||||||
|
AdapterBackend.addAdapter(newAdapter)
|
||||||
|
.then((res) => {
|
||||||
|
this.props.history.push({pathname: `/adapters/${newAdapter.owner}/${newAdapter.name}`, mode: "add"});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `Adapter failed to add: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteAdapter(i) {
|
||||||
|
AdapterBackend.deleteAdapter(this.state.data[i])
|
||||||
|
.then((res) => {
|
||||||
|
Setting.showMessage("success", "Adapter deleted successfully");
|
||||||
|
this.setState({
|
||||||
|
data: Setting.deleteRow(this.state.data, i),
|
||||||
|
pagination: {total: this.state.pagination.total - 1},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `Adapter failed to delete: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(adapters) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Organization"),
|
||||||
|
dataIndex: "organization",
|
||||||
|
key: "organization",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("organization"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/organizations/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Name"),
|
||||||
|
dataIndex: "name",
|
||||||
|
key: "name",
|
||||||
|
width: "150px",
|
||||||
|
fixed: "left",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("name"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/adapters/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Created time"),
|
||||||
|
dataIndex: "createdTime",
|
||||||
|
key: "createdTime",
|
||||||
|
width: "160px",
|
||||||
|
sorter: true,
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return Setting.getFormattedDate(text);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("provider:Type"),
|
||||||
|
dataIndex: "type",
|
||||||
|
key: "type",
|
||||||
|
width: "100px",
|
||||||
|
sorter: true,
|
||||||
|
filterMultiple: false,
|
||||||
|
filters: [
|
||||||
|
{text: "Database", value: "Database"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("provider:Host"),
|
||||||
|
dataIndex: "host",
|
||||||
|
key: "host",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("host"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("provider:Port"),
|
||||||
|
dataIndex: "port",
|
||||||
|
key: "port",
|
||||||
|
width: "100px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("port"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:User"),
|
||||||
|
dataIndex: "user",
|
||||||
|
key: "user",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("user"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Password"),
|
||||||
|
dataIndex: "password",
|
||||||
|
key: "password",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
...this.getColumnSearchProps("password"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("syncer:Database type"),
|
||||||
|
dataIndex: "databaseType",
|
||||||
|
key: "databaseType",
|
||||||
|
width: "120px",
|
||||||
|
sorter: (a, b) => a.databaseType.localeCompare(b.databaseType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("syncer:Database"),
|
||||||
|
dataIndex: "database",
|
||||||
|
key: "database",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("syncer:Table"),
|
||||||
|
dataIndex: "table",
|
||||||
|
key: "table",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Is enabled"),
|
||||||
|
dataIndex: "isEnabled",
|
||||||
|
key: "isEnabled",
|
||||||
|
width: "120px",
|
||||||
|
sorter: true,
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Action"),
|
||||||
|
dataIndex: "",
|
||||||
|
key: "op",
|
||||||
|
width: "170px",
|
||||||
|
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/adapters/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||||
|
<Popconfirm
|
||||||
|
title={`Sure to delete adapter: ${record.name} ?`}
|
||||||
|
onConfirm={() => this.deleteAdapter(index)}
|
||||||
|
>
|
||||||
|
<Button style={{marginBottom: "10px"}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const paginationProps = {
|
||||||
|
total: this.state.pagination.total,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table scroll={{x: "max-content"}} columns={columns} dataSource={adapters} rowKey="name" size="middle" bordered pagination={paginationProps}
|
||||||
|
title={() => (
|
||||||
|
<div>
|
||||||
|
{i18next.t("general:Adapters")}
|
||||||
|
<Button type="primary" size="small" onClick={this.addAdapter.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
loading={this.state.loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
let field = params.searchedColumn, value = params.searchText;
|
||||||
|
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||||
|
if (params.type !== undefined && params.type !== null) {
|
||||||
|
field = "type";
|
||||||
|
value = params.type;
|
||||||
|
}
|
||||||
|
this.setState({loading: true});
|
||||||
|
AdapterBackend.getAdapters("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
data: res.data,
|
||||||
|
pagination: {
|
||||||
|
...params.pagination,
|
||||||
|
total: res.data2,
|
||||||
|
},
|
||||||
|
searchText: params.searchText,
|
||||||
|
searchedColumn: params.searchedColumn,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdapterListPage;
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user