mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-08 22:17:53 +08:00
Compare commits
103 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8ede4993af | ||
![]() |
d04dd33d8b | ||
![]() |
8cb21253f6 | ||
![]() |
7fc697b711 | ||
![]() |
80e6e7f0a7 | ||
![]() |
d29fc88d68 | ||
![]() |
225e9cf70a | ||
![]() |
c57c6e37dd | ||
![]() |
4d860525bf | ||
![]() |
a64263f812 | ||
![]() |
95ab2472ce | ||
![]() |
54e4747dbc | ||
![]() |
2389d47c34 | ||
![]() |
9c4f0f042e | ||
![]() |
e25e210b06 | ||
![]() |
df61a536c1 | ||
![]() |
47da3cdaa0 | ||
![]() |
8d246f2d98 | ||
![]() |
44cd55e55f | ||
![]() |
6b42d35223 | ||
![]() |
c84150cede | ||
![]() |
de2689ac39 | ||
![]() |
88c0856d17 | ||
![]() |
319031da28 | ||
![]() |
d20f3eb039 | ||
![]() |
3e13e61d8f | ||
![]() |
1260354b36 | ||
![]() |
af79fdedf2 | ||
![]() |
02333f2f0c | ||
![]() |
79bd58e0e6 | ||
![]() |
de73ff0e60 | ||
![]() |
a9d662f1bd | ||
![]() |
65dcbd2236 | ||
![]() |
6455734807 | ||
![]() |
2eefeaffa7 | ||
![]() |
04eaad1c80 | ||
![]() |
9f084a0799 | ||
![]() |
293b9f1036 | ||
![]() |
437376c472 | ||
![]() |
cc528c5d8c | ||
![]() |
54e2055ffb | ||
![]() |
983a30a2e0 | ||
![]() |
37d0157d41 | ||
![]() |
d4dc236770 | ||
![]() |
596742d782 | ||
![]() |
ce921c00cd | ||
![]() |
3830e443b0 | ||
![]() |
9092cad631 | ||
![]() |
0b5ecca5c8 | ||
![]() |
3d9b305bbb | ||
![]() |
0217e359e7 | ||
![]() |
695a612e77 | ||
![]() |
645d53e2c6 | ||
![]() |
73b9d73f64 | ||
![]() |
c6675ee4e6 | ||
![]() |
6f0b7f3f24 | ||
![]() |
776a682fae | ||
![]() |
96a3db21a1 | ||
![]() |
c33d537ac1 | ||
![]() |
5214d48486 | ||
![]() |
e360b06d12 | ||
![]() |
3c871c38df | ||
![]() |
7df043fb15 | ||
![]() |
cb542ae46a | ||
![]() |
3699177837 | ||
![]() |
3a6846b32c | ||
![]() |
50586a9716 | ||
![]() |
9201992140 | ||
![]() |
eb39e9e044 | ||
![]() |
5b27f939b8 | ||
![]() |
69ee6a6f7e | ||
![]() |
bf6d5e529b | ||
![]() |
55fd31f575 | ||
![]() |
05c063ac24 | ||
![]() |
38da63e73c | ||
![]() |
cb13d693e6 | ||
![]() |
d699774179 | ||
![]() |
84a7fdcd07 | ||
![]() |
2cd6f9df8e | ||
![]() |
eea2e1d271 | ||
![]() |
48c5bd942c | ||
![]() |
d01d63d82a | ||
![]() |
e4fd9cca92 | ||
![]() |
8d531b8880 | ||
![]() |
b1589e11eb | ||
![]() |
b32a772a77 | ||
![]() |
7e4562efe1 | ||
![]() |
3a6ab4cfc6 | ||
![]() |
fba4801a41 | ||
![]() |
da21c92815 | ||
![]() |
66c15578b1 | ||
![]() |
f272be67ab | ||
![]() |
e4c36d407f | ||
![]() |
4c1915b014 | ||
![]() |
6c2b172aae | ||
![]() |
95f4f4cb6d | ||
![]() |
511aefb706 | ||
![]() |
1003639e5b | ||
![]() |
fe53e90d37 | ||
![]() |
8c73cb5395 | ||
![]() |
06ebc04032 | ||
![]() |
0ee98e2582 | ||
![]() |
d25508fa56 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.16.5'
|
||||||
cache-dependency-path: ./go.mod
|
cache: false
|
||||||
|
|
||||||
# gen a dummy config file
|
# gen a dummy config file
|
||||||
- run: touch dummy.yml
|
- run: touch dummy.yml
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -29,4 +29,6 @@ lastupdate.tmp
|
|||||||
commentsRouter*.go
|
commentsRouter*.go
|
||||||
|
|
||||||
# ignore build result
|
# ignore build result
|
||||||
casdoor
|
casdoor
|
||||||
|
server_linux_arm64
|
||||||
|
server_linux_amd64
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
FROM node:16.13.0 AS FRONT
|
FROM node:16.18.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 --frozen-lockfile --network-timeout 1000000 && yarn run build
|
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
|
||||||
|
|
||||||
|
|
||||||
FROM golang:1.17.5 AS BACK
|
FROM golang:1.19.9 AS BACK
|
||||||
WORKDIR /go/src/casdoor
|
WORKDIR /go/src/casdoor
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN ./build.sh
|
RUN ./build.sh
|
||||||
|
141
ai/ai.go
Normal file
141
ai/ai.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// Copyright 2023 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 ai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func queryAnswer(authToken string, question string, timeout int) (string, error) {
|
||||||
|
// fmt.Printf("Question: %s\n", question)
|
||||||
|
|
||||||
|
client := getProxyClientFromToken(authToken)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(2+timeout*2)*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resp, err := client.CreateChatCompletion(
|
||||||
|
ctx,
|
||||||
|
openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT3Dot5Turbo,
|
||||||
|
Messages: []openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: question,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := resp.Choices[0].Message.Content
|
||||||
|
res = strings.Trim(res, "\n")
|
||||||
|
// fmt.Printf("Answer: %s\n\n", res)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryAnswerSafe(authToken string, question string) string {
|
||||||
|
var res string
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
res, err = queryAnswer(authToken, question, i)
|
||||||
|
if err != nil {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryAnswerStream(authToken string, question string, writer io.Writer, builder *strings.Builder) error {
|
||||||
|
client := getProxyClientFromToken(authToken)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
flusher, ok := writer.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("writer does not implement http.Flusher")
|
||||||
|
}
|
||||||
|
// https://platform.openai.com/tokenizer
|
||||||
|
// https://github.com/pkoukk/tiktoken-go#available-encodings
|
||||||
|
promptTokens, err := getTokenSize(openai.GPT3TextDavinci003, question)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://platform.openai.com/docs/models/gpt-3-5
|
||||||
|
maxTokens := 4097 - promptTokens
|
||||||
|
|
||||||
|
respStream, err := client.CreateCompletionStream(
|
||||||
|
ctx,
|
||||||
|
openai.CompletionRequest{
|
||||||
|
Model: openai.GPT3TextDavinci003,
|
||||||
|
Prompt: question,
|
||||||
|
MaxTokens: maxTokens,
|
||||||
|
Stream: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer respStream.Close()
|
||||||
|
|
||||||
|
isLeadingReturn := true
|
||||||
|
for {
|
||||||
|
completion, streamErr := respStream.Recv()
|
||||||
|
if streamErr != nil {
|
||||||
|
if streamErr == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return streamErr
|
||||||
|
}
|
||||||
|
|
||||||
|
data := completion.Choices[0].Text
|
||||||
|
if isLeadingReturn && len(data) != 0 {
|
||||||
|
if strings.Count(data, "\n") == len(data) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
isLeadingReturn = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s", data)
|
||||||
|
|
||||||
|
// Write the streamed data as Server-Sent Events
|
||||||
|
if _, err = fmt.Fprintf(writer, "data: %s\n\n", data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flusher.Flush()
|
||||||
|
// Append the response to the strings.Builder
|
||||||
|
builder.WriteString(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
42
ai/ai_test.go
Normal file
42
ai/ai_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2023 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 ai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/proxy"
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRun(t *testing.T) {
|
||||||
|
object.InitConfig()
|
||||||
|
proxy.InitHttpClient()
|
||||||
|
|
||||||
|
text, err := queryAnswer("", "hi", 5)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
println(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToken(t *testing.T) {
|
||||||
|
println(getTokenSize(openai.GPT3TextDavinci003, ""))
|
||||||
|
}
|
28
ai/proxy.go
Normal file
28
ai/proxy.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2023 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 ai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/casdoor/casdoor/proxy"
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getProxyClientFromToken(authToken string) *openai.Client {
|
||||||
|
config := openai.DefaultConfig(authToken)
|
||||||
|
config.HTTPClient = proxy.ProxyHttpClient
|
||||||
|
|
||||||
|
c := openai.NewClientWithConfig(config)
|
||||||
|
return c
|
||||||
|
}
|
28
ai/util.go
Normal file
28
ai/util.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2023 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 ai
|
||||||
|
|
||||||
|
import "github.com/pkoukk/tiktoken-go"
|
||||||
|
|
||||||
|
func getTokenSize(model string, prompt string) (int, error) {
|
||||||
|
tkm, err := tiktoken.EncodingForModel(model)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := tkm.Encode(prompt, nil, nil)
|
||||||
|
res := len(token)
|
||||||
|
return res, nil
|
||||||
|
}
|
@@ -15,13 +15,13 @@
|
|||||||
package authz
|
package authz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/casbin/casbin/v2"
|
"github.com/casbin/casbin/v2"
|
||||||
"github.com/casbin/casbin/v2/model"
|
"github.com/casbin/casbin/v2/model"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||||
stringadapter "github.com/qiangmzsx/string-adapter/v2"
|
stringadapter "github.com/qiangmzsx/string-adapter/v2"
|
||||||
)
|
)
|
||||||
@@ -88,6 +88,7 @@ p, *, *, GET, /api/logout, *, *
|
|||||||
p, *, *, GET, /api/get-account, *, *
|
p, *, *, GET, /api/get-account, *, *
|
||||||
p, *, *, GET, /api/userinfo, *, *
|
p, *, *, GET, /api/userinfo, *, *
|
||||||
p, *, *, GET, /api/user, *, *
|
p, *, *, GET, /api/user, *, *
|
||||||
|
p, *, *, GET, /api/health, *, *
|
||||||
p, *, *, POST, /api/webhook, *, *
|
p, *, *, POST, /api/webhook, *, *
|
||||||
p, *, *, GET, /api/get-webhook-event, *, *
|
p, *, *, GET, /api/get-webhook-event, *, *
|
||||||
p, *, *, GET, /api/get-captcha-status, *, *
|
p, *, *, GET, /api/get-captcha-status, *, *
|
||||||
@@ -121,6 +122,12 @@ p, *, *, *, /cas, *, *
|
|||||||
p, *, *, *, /api/webauthn, *, *
|
p, *, *, *, /api/webauthn, *, *
|
||||||
p, *, *, GET, /api/get-release, *, *
|
p, *, *, GET, /api/get-release, *, *
|
||||||
p, *, *, GET, /api/get-default-application, *, *
|
p, *, *, GET, /api/get-default-application, *, *
|
||||||
|
p, *, *, GET, /api/get-prometheus-info, *, *
|
||||||
|
p, *, *, *, /api/metrics, *, *
|
||||||
|
p, *, *, GET, /api/get-subscriptions, *, *
|
||||||
|
p, *, *, GET, /api/get-pricing, *, *
|
||||||
|
p, *, *, GET, /api/get-plan, *, *
|
||||||
|
p, *, *, GET, /api/get-organization-names, *, *
|
||||||
`
|
`
|
||||||
|
|
||||||
sa := stringadapter.NewAdapter(ruleText)
|
sa := stringadapter.NewAdapter(ruleText)
|
||||||
@@ -147,9 +154,8 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userId := fmt.Sprintf("%s/%s", subOwner, subName)
|
user := object.GetUser(util.GetId(subOwner, subName))
|
||||||
user := object.GetUser(userId)
|
if user != nil && user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
|
||||||
if user != nil && user.IsAdmin && (subOwner == objOwner || (objOwner == "admin" && subOwner == objName)) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,5 +20,4 @@ staticBaseUrl = "https://cdn.casbin.org"
|
|||||||
isDemoMode = false
|
isDemoMode = false
|
||||||
batchSize = 100
|
batchSize = 100
|
||||||
ldapServerPort = 389
|
ldapServerPort = 389
|
||||||
languages = en,zh,es,fr,de,id,ja,ko,ru,vi
|
|
||||||
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
|
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
|
||||||
|
@@ -112,13 +112,8 @@ func GetLanguage(language string) string {
|
|||||||
|
|
||||||
if len(language) < 2 {
|
if len(language) < 2 {
|
||||||
return "en"
|
return "en"
|
||||||
}
|
|
||||||
|
|
||||||
language = language[0:2]
|
|
||||||
if strings.Contains(GetConfigString("languages"), language) {
|
|
||||||
return language
|
|
||||||
} else {
|
} else {
|
||||||
return "en"
|
return language[0:2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/form"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@@ -34,44 +35,6 @@ const (
|
|||||||
ResponseTypeCas = "cas"
|
ResponseTypeCas = "cas"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RequestForm struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
|
|
||||||
Organization string `json:"organization"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
FirstName string `json:"firstName"`
|
|
||||||
LastName string `json:"lastName"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Phone string `json:"phone"`
|
|
||||||
Affiliation string `json:"affiliation"`
|
|
||||||
IdCard string `json:"idCard"`
|
|
||||||
Region string `json:"region"`
|
|
||||||
|
|
||||||
Application string `json:"application"`
|
|
||||||
ClientId string `json:"clientId"`
|
|
||||||
Provider string `json:"provider"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
State string `json:"state"`
|
|
||||||
RedirectUri string `json:"redirectUri"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
|
|
||||||
EmailCode string `json:"emailCode"`
|
|
||||||
PhoneCode string `json:"phoneCode"`
|
|
||||||
CountryCode string `json:"countryCode"`
|
|
||||||
|
|
||||||
AutoSignin bool `json:"autoSignin"`
|
|
||||||
|
|
||||||
RelayState string `json:"relayState"`
|
|
||||||
SamlRequest string `json:"samlRequest"`
|
|
||||||
SamlResponse string `json:"samlResponse"`
|
|
||||||
|
|
||||||
CaptchaType string `json:"captchaType"`
|
|
||||||
CaptchaToken string `json:"captchaToken"`
|
|
||||||
ClientSecret string `json:"clientSecret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Msg string `json:"msg"`
|
Msg string `json:"msg"`
|
||||||
@@ -108,28 +71,28 @@ func (c *ApiController) Signup() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var form RequestForm
|
var authForm form.AuthForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application := object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
if !application.EnableSignUp {
|
if !application.EnableSignUp {
|
||||||
c.ResponseError(c.T("account:The application does not allow to sign up new account"))
|
c.ResponseError(c.T("account:The application does not allow to sign up new account"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", form.Organization))
|
organization := object.GetOrganization(util.GetId("admin", authForm.Organization))
|
||||||
msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.FirstName, form.LastName, form.Email, form.Phone, form.CountryCode, form.Affiliation, c.GetAcceptLanguage())
|
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
c.ResponseError(msg)
|
c.ResponseError(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && form.Email != "" {
|
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && authForm.Email != "" {
|
||||||
checkResult := object.CheckVerificationCode(form.Email, form.EmailCode, c.GetAcceptLanguage())
|
checkResult := object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
|
||||||
if checkResult.Code != object.VerificationSuccess {
|
if checkResult.Code != object.VerificationSuccess {
|
||||||
c.ResponseError(checkResult.Msg)
|
c.ResponseError(checkResult.Msg)
|
||||||
return
|
return
|
||||||
@@ -137,9 +100,9 @@ func (c *ApiController) Signup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var checkPhone string
|
var checkPhone string
|
||||||
if application.IsSignupItemVisible("Phone") && application.GetSignupItemRule("Phone") != "No verification" && form.Phone != "" {
|
if application.IsSignupItemVisible("Phone") && application.GetSignupItemRule("Phone") != "No verification" && authForm.Phone != "" {
|
||||||
checkPhone, _ = util.GetE164Number(form.Phone, form.CountryCode)
|
checkPhone, _ = util.GetE164Number(authForm.Phone, authForm.CountryCode)
|
||||||
checkResult := object.CheckVerificationCode(checkPhone, form.PhoneCode, c.GetAcceptLanguage())
|
checkResult := object.CheckVerificationCode(checkPhone, authForm.PhoneCode, c.GetAcceptLanguage())
|
||||||
if checkResult.Code != object.VerificationSuccess {
|
if checkResult.Code != object.VerificationSuccess {
|
||||||
c.ResponseError(checkResult.Msg)
|
c.ResponseError(checkResult.Msg)
|
||||||
return
|
return
|
||||||
@@ -148,7 +111,7 @@ func (c *ApiController) Signup() {
|
|||||||
|
|
||||||
id := util.GenerateId()
|
id := util.GenerateId()
|
||||||
if application.GetSignupItemRule("ID") == "Incremental" {
|
if application.GetSignupItemRule("ID") == "Incremental" {
|
||||||
lastUser := object.GetLastUser(form.Organization)
|
lastUser := object.GetLastUser(authForm.Organization)
|
||||||
|
|
||||||
lastIdInt := -1
|
lastIdInt := -1
|
||||||
if lastUser != nil {
|
if lastUser != nil {
|
||||||
@@ -158,33 +121,33 @@ func (c *ApiController) Signup() {
|
|||||||
id = strconv.Itoa(lastIdInt + 1)
|
id = strconv.Itoa(lastIdInt + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
username := form.Username
|
username := authForm.Username
|
||||||
if !application.IsSignupItemVisible("Username") {
|
if !application.IsSignupItemVisible("Username") {
|
||||||
username = id
|
username = id
|
||||||
}
|
}
|
||||||
|
|
||||||
initScore, err := getInitScore(organization)
|
initScore, err := organization.GetInitScore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := &object.User{
|
user := &object.User{
|
||||||
Owner: form.Organization,
|
Owner: authForm.Organization,
|
||||||
Name: username,
|
Name: username,
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
Id: id,
|
Id: id,
|
||||||
Type: "normal-user",
|
Type: "normal-user",
|
||||||
Password: form.Password,
|
Password: authForm.Password,
|
||||||
DisplayName: form.Name,
|
DisplayName: authForm.Name,
|
||||||
Avatar: organization.DefaultAvatar,
|
Avatar: organization.DefaultAvatar,
|
||||||
Email: form.Email,
|
Email: authForm.Email,
|
||||||
Phone: form.Phone,
|
Phone: authForm.Phone,
|
||||||
CountryCode: form.CountryCode,
|
CountryCode: authForm.CountryCode,
|
||||||
Address: []string{},
|
Address: []string{},
|
||||||
Affiliation: form.Affiliation,
|
Affiliation: authForm.Affiliation,
|
||||||
IdCard: form.IdCard,
|
IdCard: authForm.IdCard,
|
||||||
Region: form.Region,
|
Region: authForm.Region,
|
||||||
Score: initScore,
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
IsGlobalAdmin: false,
|
||||||
@@ -203,10 +166,10 @@ func (c *ApiController) Signup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if application.GetSignupItemRule("Display name") == "First, last" {
|
if application.GetSignupItemRule("Display name") == "First, last" {
|
||||||
if form.FirstName != "" || form.LastName != "" {
|
if authForm.FirstName != "" || authForm.LastName != "" {
|
||||||
user.DisplayName = fmt.Sprintf("%s %s", form.FirstName, form.LastName)
|
user.DisplayName = fmt.Sprintf("%s %s", authForm.FirstName, authForm.LastName)
|
||||||
user.FirstName = form.FirstName
|
user.FirstName = authForm.FirstName
|
||||||
user.LastName = form.LastName
|
user.LastName = authForm.LastName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,9 +186,14 @@ func (c *ApiController) Signup() {
|
|||||||
c.SetSessionUsername(user.GetId())
|
c.SetSessionUsername(user.GetId())
|
||||||
}
|
}
|
||||||
|
|
||||||
object.DisableVerificationCode(form.Email)
|
object.DisableVerificationCode(authForm.Email)
|
||||||
object.DisableVerificationCode(checkPhone)
|
object.DisableVerificationCode(checkPhone)
|
||||||
|
|
||||||
|
isSignupFromPricing := authForm.Plan != "" && authForm.Pricing != ""
|
||||||
|
if isSignupFromPricing {
|
||||||
|
object.Subscribe(organization.Name, user.Name, authForm.Plan, authForm.Pricing)
|
||||||
|
}
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
record.User = user.Name
|
record.User = user.Name
|
||||||
|
@@ -118,8 +118,7 @@ func (c *ApiController) GetOrganizationApplications() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
var applications []*object.Application
|
applications := object.GetOrganizationApplications(owner, organization)
|
||||||
applications = object.GetOrganizationApplications(owner, organization)
|
|
||||||
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
|
@@ -24,10 +24,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/captcha"
|
"github.com/casdoor/casdoor/captcha"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
"github.com/casdoor/casdoor/form"
|
||||||
"github.com/casdoor/casdoor/idp"
|
"github.com/casdoor/casdoor/idp"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/proxy"
|
"github.com/casdoor/casdoor/proxy"
|
||||||
@@ -56,7 +56,7 @@ func tokenToResponse(token *object.Token) *Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleLoggedIn ...
|
// HandleLoggedIn ...
|
||||||
func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *RequestForm) (resp *Response) {
|
func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *form.AuthForm) (resp *Response) {
|
||||||
userId := user.GetId()
|
userId := user.GetId()
|
||||||
|
|
||||||
allowed, err := object.CheckAccessPermission(userId, application)
|
allowed, err := object.CheckAccessPermission(userId, application)
|
||||||
@@ -69,6 +69,12 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Password != "" && user.IsMfaEnabled() {
|
||||||
|
c.setMfaSessionData(&object.MfaSessionData{UserId: userId})
|
||||||
|
resp = &Response{Status: object.NextMfa, Data: user.GetPreferMfa(true)}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if form.Type == ResponseTypeLogin {
|
if form.Type == ResponseTypeLogin {
|
||||||
c.SetSessionUsername(userId)
|
c.SetSessionUsername(userId)
|
||||||
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
||||||
@@ -132,14 +138,10 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
|||||||
|
|
||||||
// if user did not check auto signin
|
// if user did not check auto signin
|
||||||
if resp.Status == "ok" && !form.AutoSignin {
|
if resp.Status == "ok" && !form.AutoSignin {
|
||||||
timestamp := time.Now().Unix()
|
c.setExpireForSession()
|
||||||
timestamp += 3600 * 24
|
|
||||||
c.SetSessionData(&SessionData{
|
|
||||||
ExpireTime: timestamp,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Status == "ok" && user.Owner == object.CasdoorOrganization && application.Name == object.CasdoorApplication {
|
if resp.Status == "ok" {
|
||||||
object.AddSession(&object.Session{
|
object.AddSession(&object.Session{
|
||||||
Owner: user.Owner,
|
Owner: user.Owner,
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
@@ -221,21 +223,21 @@ func isProxyProviderType(providerType string) bool {
|
|||||||
// @Param nonce query string false nonce
|
// @Param nonce query string false nonce
|
||||||
// @Param code_challenge_method query string false code_challenge_method
|
// @Param code_challenge_method query string false code_challenge_method
|
||||||
// @Param code_challenge query string false code_challenge
|
// @Param code_challenge query string false code_challenge
|
||||||
// @Param form body controllers.RequestForm true "Login information"
|
// @Param form body controllers.AuthForm true "Login information"
|
||||||
// @Success 200 {object} Response The Response object
|
// @Success 200 {object} Response The Response object
|
||||||
// @router /login [post]
|
// @router /login [post]
|
||||||
func (c *ApiController) Login() {
|
func (c *ApiController) Login() {
|
||||||
resp := &Response{}
|
resp := &Response{}
|
||||||
|
|
||||||
var form RequestForm
|
var authForm form.AuthForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Username != "" {
|
if authForm.Username != "" {
|
||||||
if form.Type == ResponseTypeLogin {
|
if authForm.Type == ResponseTypeLogin {
|
||||||
if c.GetSessionUsername() != "" {
|
if c.GetSessionUsername() != "" {
|
||||||
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
|
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
|
||||||
return
|
return
|
||||||
@@ -245,25 +247,25 @@ func (c *ApiController) Login() {
|
|||||||
var user *object.User
|
var user *object.User
|
||||||
var msg string
|
var msg string
|
||||||
|
|
||||||
if form.Password == "" {
|
if authForm.Password == "" {
|
||||||
if user = object.GetUserByFields(form.Organization, form.Username); user == nil {
|
if user = object.GetUserByFields(authForm.Organization, authForm.Username); user == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username)))
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(authForm.Organization, authForm.Username)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationCodeType := object.GetVerifyType(form.Username)
|
verificationCodeType := object.GetVerifyType(authForm.Username)
|
||||||
var checkDest string
|
var checkDest string
|
||||||
if verificationCodeType == object.VerifyTypePhone {
|
if verificationCodeType == object.VerifyTypePhone {
|
||||||
form.CountryCode = user.GetCountryCode(form.CountryCode)
|
authForm.CountryCode = user.GetCountryCode(authForm.CountryCode)
|
||||||
var ok bool
|
var ok bool
|
||||||
if checkDest, ok = util.GetE164Number(form.Username, form.CountryCode); !ok {
|
if checkDest, ok = util.GetE164Number(authForm.Username, authForm.CountryCode); !ok {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), form.CountryCode))
|
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), authForm.CountryCode))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check result through Email or Phone
|
// check result through Email or Phone
|
||||||
checkResult := object.CheckSigninCode(user, checkDest, form.Code, c.GetAcceptLanguage())
|
checkResult := object.CheckSigninCode(user, checkDest, authForm.Code, c.GetAcceptLanguage())
|
||||||
if len(checkResult) != 0 {
|
if len(checkResult) != 0 {
|
||||||
c.ResponseError(fmt.Sprintf("%s - %s", verificationCodeType, checkResult))
|
c.ResponseError(fmt.Sprintf("%s - %s", verificationCodeType, checkResult))
|
||||||
return
|
return
|
||||||
@@ -272,9 +274,9 @@ func (c *ApiController) Login() {
|
|||||||
// disable the verification code
|
// disable the verification code
|
||||||
object.DisableVerificationCode(checkDest)
|
object.DisableVerificationCode(checkDest)
|
||||||
} else {
|
} else {
|
||||||
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application := object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
if application == nil {
|
if application == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !application.EnablePassword {
|
if !application.EnablePassword {
|
||||||
@@ -282,8 +284,8 @@ func (c *ApiController) Login() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var enableCaptcha bool
|
var enableCaptcha bool
|
||||||
if enableCaptcha = object.CheckToEnableCaptcha(application, form.Organization, form.Username); enableCaptcha {
|
if enableCaptcha = object.CheckToEnableCaptcha(application, authForm.Organization, authForm.Username); enableCaptcha {
|
||||||
isHuman, err := captcha.VerifyCaptchaByCaptchaType(form.CaptchaType, form.CaptchaToken, form.ClientSecret)
|
isHuman, err := captcha.VerifyCaptchaByCaptchaType(authForm.CaptchaType, authForm.CaptchaToken, authForm.ClientSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -295,42 +297,46 @@ func (c *ApiController) Login() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
password := form.Password
|
password := authForm.Password
|
||||||
user, msg = object.CheckUserPassword(form.Organization, form.Username, password, c.GetAcceptLanguage(), enableCaptcha)
|
user, msg = object.CheckUserPassword(authForm.Organization, authForm.Username, password, c.GetAcceptLanguage(), enableCaptcha)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
resp = &Response{Status: "error", Msg: msg}
|
resp = &Response{Status: "error", Msg: msg}
|
||||||
} else {
|
} else {
|
||||||
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application := object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
if application == nil {
|
if application == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = c.HandleLoggedIn(application, user, &form)
|
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||||
|
|
||||||
|
organization := object.GetOrganizationByUser(user)
|
||||||
|
if user != nil && organization.HasRequiredMfa() && !user.IsMfaEnabled() {
|
||||||
|
resp.Msg = object.RequiredMfa
|
||||||
|
}
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
record.User = user.Name
|
record.User = user.Name
|
||||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||||
}
|
}
|
||||||
} else if form.Provider != "" {
|
} else if authForm.Provider != "" {
|
||||||
var application *object.Application
|
var application *object.Application
|
||||||
if form.ClientId != "" {
|
if authForm.ClientId != "" {
|
||||||
application = object.GetApplicationByClientId(form.ClientId)
|
application = object.GetApplicationByClientId(authForm.ClientId)
|
||||||
} else {
|
} else {
|
||||||
application = object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
}
|
}
|
||||||
|
|
||||||
if application == nil {
|
if application == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", application.Organization))
|
organization := object.GetOrganization(util.GetId("admin", application.Organization))
|
||||||
provider := object.GetProvider(util.GetId("admin", form.Provider))
|
provider := object.GetProvider(util.GetId("admin", authForm.Provider))
|
||||||
providerItem := application.GetProviderItem(provider.Name)
|
providerItem := application.GetProviderItem(provider.Name)
|
||||||
if !providerItem.IsProviderVisible() {
|
if !providerItem.IsProviderVisible() {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s is not enabled for the application"), provider.Name))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s is not enabled for the application"), provider.Name))
|
||||||
@@ -340,7 +346,7 @@ func (c *ApiController) Login() {
|
|||||||
userInfo := &idp.UserInfo{}
|
userInfo := &idp.UserInfo{}
|
||||||
if provider.Category == "SAML" {
|
if provider.Category == "SAML" {
|
||||||
// SAML
|
// SAML
|
||||||
userInfo.Id, err = object.ParseSamlResponse(form.SamlResponse, provider, c.Ctx.Request.Host)
|
userInfo.Id, err = object.ParseSamlResponse(authForm.SamlResponse, provider, c.Ctx.Request.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -355,7 +361,7 @@ func (c *ApiController) Login() {
|
|||||||
clientSecret = provider.ClientSecret2
|
clientSecret = provider.ClientSecret2
|
||||||
}
|
}
|
||||||
|
|
||||||
idProvider := idp.GetIdProvider(provider.Type, provider.SubType, clientId, clientSecret, provider.AppId, form.RedirectUri, provider.Domain, provider.CustomAuthUrl, provider.CustomTokenUrl, provider.CustomUserInfoUrl)
|
idProvider := idp.GetIdProvider(provider.Type, provider.SubType, clientId, clientSecret, provider.AppId, authForm.RedirectUri, provider.Domain, provider.CustomAuthUrl, provider.CustomTokenUrl, provider.CustomUserInfoUrl)
|
||||||
if idProvider == nil {
|
if idProvider == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("storage:The provider type: %s is not supported"), provider.Type))
|
c.ResponseError(fmt.Sprintf(c.T("storage:The provider type: %s is not supported"), provider.Type))
|
||||||
return
|
return
|
||||||
@@ -363,13 +369,13 @@ func (c *ApiController) Login() {
|
|||||||
|
|
||||||
setHttpClient(idProvider, provider.Type)
|
setHttpClient(idProvider, provider.Type)
|
||||||
|
|
||||||
if form.State != conf.GetConfigString("authState") && form.State != application.Name {
|
if authForm.State != conf.GetConfigString("authState") && authForm.State != application.Name {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:State expected: %s, but got: %s"), conf.GetConfigString("authState"), form.State))
|
c.ResponseError(fmt.Sprintf(c.T("auth:State expected: %s, but got: %s"), conf.GetConfigString("authState"), authForm.State))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/golang/oauth2/issues/123#issuecomment-103715338
|
// https://github.com/golang/oauth2/issues/123#issuecomment-103715338
|
||||||
token, err := idProvider.GetToken(form.Code)
|
token, err := idProvider.GetToken(authForm.Code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@@ -387,10 +393,10 @@ func (c *ApiController) Login() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Method == "signup" {
|
if authForm.Method == "signup" {
|
||||||
user := &object.User{}
|
user := &object.User{}
|
||||||
if provider.Category == "SAML" {
|
if provider.Category == "SAML" {
|
||||||
user = object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Id))
|
user = object.GetUser(util.GetId(application.Organization, userInfo.Id))
|
||||||
} else if provider.Category == "OAuth" {
|
} else if provider.Category == "OAuth" {
|
||||||
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
|
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
|
||||||
}
|
}
|
||||||
@@ -402,7 +408,7 @@ func (c *ApiController) Login() {
|
|||||||
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
|
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = c.HandleLoggedIn(application, user, &form)
|
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
@@ -410,24 +416,31 @@ func (c *ApiController) Login() {
|
|||||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||||
} else if provider.Category == "OAuth" {
|
} else if provider.Category == "OAuth" {
|
||||||
// Sign up via OAuth
|
// Sign up via OAuth
|
||||||
if !application.EnableSignUp {
|
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !providerItem.CanSignUp {
|
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if application.EnableLinkWithEmail {
|
if application.EnableLinkWithEmail {
|
||||||
// find user that has the same email
|
if userInfo.Email != "" {
|
||||||
user = object.GetUserByField(application.Organization, "email", userInfo.Email)
|
// Find existing user with Email
|
||||||
|
user = object.GetUserByField(application.Organization, "email", userInfo.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user == nil && userInfo.Phone != "" {
|
||||||
|
// Find existing user with phone number
|
||||||
|
user = object.GetUserByField(application.Organization, "phone", userInfo.Phone)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if user == nil || user.IsDeleted {
|
if user == nil || user.IsDeleted {
|
||||||
|
if !application.EnableSignUp {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !providerItem.CanSignUp {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Handle username conflicts
|
// Handle username conflicts
|
||||||
tmpUser := object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Username))
|
tmpUser := object.GetUser(util.GetId(application.Organization, userInfo.Username))
|
||||||
if tmpUser != nil {
|
if tmpUser != nil {
|
||||||
uid, err := uuid.NewRandom()
|
uid, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -441,7 +454,7 @@ func (c *ApiController) Login() {
|
|||||||
|
|
||||||
properties := map[string]string{}
|
properties := map[string]string{}
|
||||||
properties["no"] = strconv.Itoa(object.GetUserCount(application.Organization, "", "") + 2)
|
properties["no"] = strconv.Itoa(object.GetUserCount(application.Organization, "", "") + 2)
|
||||||
initScore, err := getInitScore(organization)
|
initScore, err := organization.GetInitScore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
|
||||||
return
|
return
|
||||||
@@ -457,6 +470,9 @@ func (c *ApiController) Login() {
|
|||||||
Avatar: userInfo.AvatarUrl,
|
Avatar: userInfo.AvatarUrl,
|
||||||
Address: []string{},
|
Address: []string{},
|
||||||
Email: userInfo.Email,
|
Email: userInfo.Email,
|
||||||
|
Phone: userInfo.Phone,
|
||||||
|
CountryCode: userInfo.CountryCode,
|
||||||
|
Region: userInfo.CountryCode,
|
||||||
Score: initScore,
|
Score: initScore,
|
||||||
IsAdmin: false,
|
IsAdmin: false,
|
||||||
IsGlobalAdmin: false,
|
IsGlobalAdmin: false,
|
||||||
@@ -477,7 +493,7 @@ func (c *ApiController) Login() {
|
|||||||
object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
|
||||||
object.LinkUserAccount(user, provider.Type, userInfo.Id)
|
object.LinkUserAccount(user, provider.Type, userInfo.Id)
|
||||||
|
|
||||||
resp = c.HandleLoggedIn(application, user, &form)
|
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
@@ -493,7 +509,7 @@ func (c *ApiController) Login() {
|
|||||||
resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
|
resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
|
||||||
}
|
}
|
||||||
// resp = &Response{Status: "ok", Msg: "", Data: res}
|
// resp = &Response{Status: "ok", Msg: "", Data: res}
|
||||||
} else { // form.Method != "signup"
|
} else { // authForm.Method != "signup"
|
||||||
userId := c.GetSessionUsername()
|
userId := c.GetSessionUsername()
|
||||||
if userId == "" {
|
if userId == "" {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id)), userInfo)
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id)), userInfo)
|
||||||
@@ -518,24 +534,56 @@ func (c *ApiController) Login() {
|
|||||||
resp = &Response{Status: "error", Msg: "Failed to link user account", Data: isLinked}
|
resp = &Response{Status: "error", Msg: "Failed to link user account", Data: isLinked}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if c.getMfaSessionData() != nil {
|
||||||
|
mfaSession := c.getMfaSessionData()
|
||||||
|
user := object.GetUser(mfaSession.UserId)
|
||||||
|
|
||||||
|
if authForm.Passcode != "" {
|
||||||
|
MfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferMfa(false))
|
||||||
|
err = MfaUtil.Verify(authForm.Passcode)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if authForm.RecoveryCode != "" {
|
||||||
|
err = object.RecoverTfs(user, authForm.RecoveryCode)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
application := object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
|
if application == nil {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||||
|
|
||||||
|
record := object.NewRecord(c.Ctx)
|
||||||
|
record.Organization = application.Organization
|
||||||
|
record.User = user.Name
|
||||||
|
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||||
} else {
|
} else {
|
||||||
if c.GetSessionUsername() != "" {
|
if c.GetSessionUsername() != "" {
|
||||||
// user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in
|
// user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in
|
||||||
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
|
application := object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
|
||||||
if application == nil {
|
if application == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), form.Application))
|
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user := c.getCurrentUser()
|
user := c.getCurrentUser()
|
||||||
resp = c.HandleLoggedIn(application, user, &form)
|
resp = c.HandleLoggedIn(application, user, &authForm)
|
||||||
|
|
||||||
record := object.NewRecord(c.Ctx)
|
record := object.NewRecord(c.Ctx)
|
||||||
record.Organization = application.Organization
|
record.Organization = application.Organization
|
||||||
record.User = user.Name
|
record.User = user.Name
|
||||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||||
} else {
|
} else {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(form)))
|
c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(authForm)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,18 +41,44 @@ type SessionData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) IsGlobalAdmin() bool {
|
func (c *ApiController) IsGlobalAdmin() bool {
|
||||||
username := c.GetSessionUsername()
|
isGlobalAdmin, _ := c.isGlobalAdmin()
|
||||||
if strings.HasPrefix(username, "app/") {
|
|
||||||
// e.g., "app/app-casnode"
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
user := object.GetUser(username)
|
return isGlobalAdmin
|
||||||
if user == nil {
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) IsAdmin() bool {
|
||||||
|
isGlobalAdmin, user := c.isGlobalAdmin()
|
||||||
|
if !isGlobalAdmin && user == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.Owner == "built-in" || user.IsGlobalAdmin
|
return isGlobalAdmin || user.IsAdmin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) isGlobalAdmin() (bool, *object.User) {
|
||||||
|
username := c.GetSessionUsername()
|
||||||
|
if strings.HasPrefix(username, "app/") {
|
||||||
|
// e.g., "app/app-casnode"
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user := c.getCurrentUser()
|
||||||
|
if user == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.Owner == "built-in" || user.IsGlobalAdmin, user
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) getCurrentUser() *object.User {
|
||||||
|
var user *object.User
|
||||||
|
userId := c.GetSessionUsername()
|
||||||
|
if userId == "" {
|
||||||
|
user = nil
|
||||||
|
} else {
|
||||||
|
user = object.GetUser(userId)
|
||||||
|
}
|
||||||
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSessionUsername ...
|
// GetSessionUsername ...
|
||||||
@@ -142,6 +168,30 @@ func (c *ApiController) SetSessionData(s *SessionData) {
|
|||||||
c.SetSession("SessionData", util.StructToJson(s))
|
c.SetSession("SessionData", util.StructToJson(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) setMfaSessionData(data *object.MfaSessionData) {
|
||||||
|
c.SetSession(object.MfaSessionUserId, data.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) getMfaSessionData() *object.MfaSessionData {
|
||||||
|
userId := c.GetSession(object.MfaSessionUserId)
|
||||||
|
if userId == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := &object.MfaSessionData{
|
||||||
|
UserId: userId.(string),
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) setExpireForSession() {
|
||||||
|
timestamp := time.Now().Unix()
|
||||||
|
timestamp += 3600 * 24
|
||||||
|
c.SetSessionData(&SessionData{
|
||||||
|
ExpireTime: timestamp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func wrapActionResponse(affected bool) *Response {
|
func wrapActionResponse(affected bool) *Response {
|
||||||
if affected {
|
if affected {
|
||||||
return &Response{Status: "ok", Msg: "", Data: "Affected"}
|
return &Response{Status: "ok", Msg: "", Data: "Affected"}
|
||||||
@@ -157,3 +207,14 @@ func wrapErrorResponse(err error) *Response {
|
|||||||
return &Response{Status: "error", Msg: err.Error()}
|
return &Response{Status: "error", Msg: err.Error()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) Finish() {
|
||||||
|
if strings.HasPrefix(c.Ctx.Input.URL(), "/api") {
|
||||||
|
startTime := c.Ctx.Input.GetData("startTime")
|
||||||
|
if startTime != nil {
|
||||||
|
latency := time.Since(startTime.(time.Time)).Milliseconds()
|
||||||
|
object.ApiLatency.WithLabelValues(c.Ctx.Input.URL(), c.Ctx.Input.Method()).Observe(float64(latency))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Controller.Finish()
|
||||||
|
}
|
||||||
|
@@ -31,13 +31,14 @@ func (c *ApiController) GetCasbinAdapters() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
organization := c.Input().Get("organization")
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
adapters := object.GetCasbinAdapters(owner)
|
adapters := object.GetCasbinAdapters(owner, organization)
|
||||||
c.ResponseOk(adapters)
|
c.ResponseOk(adapters)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, organization, field, value)))
|
||||||
adapters := object.GetPaginationCasbinAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
adapters := object.GetPaginationCasbinAdapters(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
c.ResponseOk(adapters, paginator.Nums())
|
c.ResponseOk(adapters, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,30 @@ func (c *ApiController) GetCerts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGlobleCerts
|
||||||
|
// @Title GetGlobleCerts
|
||||||
|
// @Tag Cert API
|
||||||
|
// @Description get globle certs
|
||||||
|
// @Success 200 {array} object.Cert The Response object
|
||||||
|
// @router /get-globle-certs [get]
|
||||||
|
func (c *ApiController) GetGlobleCerts() {
|
||||||
|
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.GetMaskedCerts(object.GetGlobleCerts())
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalCertsCount(field, value)))
|
||||||
|
certs := object.GetMaskedCerts(object.GetPaginationGlobalCerts(paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||||
|
c.ResponseOk(certs, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetCert
|
// GetCert
|
||||||
// @Title GetCert
|
// @Title GetCert
|
||||||
// @Tag Cert API
|
// @Tag Cert API
|
||||||
|
@@ -30,7 +30,7 @@ import (
|
|||||||
// @Success 200 {array} object.Chat The Response object
|
// @Success 200 {array} object.Chat The Response object
|
||||||
// @router /get-chats [get]
|
// @router /get-chats [get]
|
||||||
func (c *ApiController) GetChats() {
|
func (c *ApiController) GetChats() {
|
||||||
owner := c.Input().Get("owner")
|
owner := "admin"
|
||||||
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")
|
||||||
|
@@ -18,30 +18,69 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *ApiController) Enforce() {
|
func (c *ApiController) Enforce() {
|
||||||
var permissionRule object.PermissionRule
|
permissionId := c.Input().Get("permissionId")
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
|
modelId := c.Input().Get("modelId")
|
||||||
|
resourceId := c.Input().Get("resourceId")
|
||||||
|
|
||||||
|
var request object.CasbinRequest
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.Enforce(&permissionRule)
|
if permissionId != "" {
|
||||||
|
c.Data["json"] = object.Enforce(permissionId, &request)
|
||||||
|
c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions := make([]*object.Permission, 0)
|
||||||
|
res := []bool{}
|
||||||
|
|
||||||
|
if modelId != "" {
|
||||||
|
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||||
|
permissions = object.GetPermissionsByModel(owner, modelName)
|
||||||
|
} else {
|
||||||
|
permissions = object.GetPermissionsByResource(resourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, permission := range permissions {
|
||||||
|
res = append(res, object.Enforce(permission.GetId(), &request))
|
||||||
|
}
|
||||||
|
c.Data["json"] = res
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) BatchEnforce() {
|
func (c *ApiController) BatchEnforce() {
|
||||||
var permissionRules []object.PermissionRule
|
permissionId := c.Input().Get("permissionId")
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
|
modelId := c.Input().Get("modelId")
|
||||||
|
|
||||||
|
var requests []object.CasbinRequest
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.BatchEnforce(permissionRules)
|
if permissionId != "" {
|
||||||
c.ServeJSON()
|
c.Data["json"] = object.BatchEnforce(permissionId, &requests)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||||
|
permissions := object.GetPermissionsByModel(owner, modelName)
|
||||||
|
|
||||||
|
res := [][]bool{}
|
||||||
|
for _, permission := range permissions {
|
||||||
|
res = append(res, object.BatchEnforce(permission.GetId(), &requests))
|
||||||
|
}
|
||||||
|
c.Data["json"] = res
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetAllObjects() {
|
func (c *ApiController) GetAllObjects() {
|
||||||
|
@@ -23,7 +23,8 @@ import (
|
|||||||
|
|
||||||
type LdapResp struct {
|
type LdapResp struct {
|
||||||
// Groups []LdapRespGroup `json:"groups"`
|
// Groups []LdapRespGroup `json:"groups"`
|
||||||
Users []object.LdapRespUser `json:"users"`
|
Users []object.LdapUser `json:"users"`
|
||||||
|
ExistUuids []string `json:"existUuids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//type LdapRespGroup struct {
|
//type LdapRespGroup struct {
|
||||||
@@ -32,8 +33,8 @@ type LdapResp struct {
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
type LdapSyncResp struct {
|
type LdapSyncResp struct {
|
||||||
Exist []object.LdapRespUser `json:"exist"`
|
Exist []object.LdapUser `json:"exist"`
|
||||||
Failed []object.LdapRespUser `json:"failed"`
|
Failed []object.LdapUser `json:"failed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLdapUsers
|
// GetLdapUsers
|
||||||
@@ -71,27 +72,17 @@ func (c *ApiController) GetLdapUsers() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp LdapResp
|
|
||||||
uuids := make([]string, len(users))
|
uuids := make([]string, len(users))
|
||||||
for _, user := range users {
|
for i, user := range users {
|
||||||
resp.Users = append(resp.Users, object.LdapRespUser{
|
uuids[i] = user.GetLdapUuid()
|
||||||
UidNumber: user.UidNumber,
|
|
||||||
Uid: user.Uid,
|
|
||||||
Cn: user.Cn,
|
|
||||||
GroupId: user.GidNumber,
|
|
||||||
// GroupName: groupsMap[user.GidNumber].Cn,
|
|
||||||
Uuid: user.Uuid,
|
|
||||||
DisplayName: user.DisplayName,
|
|
||||||
Email: util.GetMaxLenStr(user.Mail, user.Email, user.EmailAddress),
|
|
||||||
Phone: util.GetMaxLenStr(user.TelephoneNumber, user.Mobile, user.MobileTelephoneNumber),
|
|
||||||
Address: util.GetMaxLenStr(user.RegisteredAddress, user.PostalAddress),
|
|
||||||
})
|
|
||||||
uuids = append(uuids, user.Uuid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
existUuids := object.GetExistUuids(ldapServer.Owner, uuids)
|
existUuids := object.GetExistUuids(ldapServer.Owner, uuids)
|
||||||
|
|
||||||
c.ResponseOk(resp, existUuids)
|
resp := LdapResp{
|
||||||
|
Users: object.AutoAdjustLdapUser(users),
|
||||||
|
ExistUuids: existUuids,
|
||||||
|
}
|
||||||
|
c.ResponseOk(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLdaps
|
// GetLdaps
|
||||||
@@ -206,7 +197,7 @@ func (c *ApiController) DeleteLdap() {
|
|||||||
func (c *ApiController) SyncLdapUsers() {
|
func (c *ApiController) SyncLdapUsers() {
|
||||||
owner := c.Input().Get("owner")
|
owner := c.Input().Get("owner")
|
||||||
ldapId := c.Input().Get("ldapId")
|
ldapId := c.Input().Get("ldapId")
|
||||||
var users []object.LdapRespUser
|
var users []object.LdapUser
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
@@ -215,10 +206,10 @@ func (c *ApiController) SyncLdapUsers() {
|
|||||||
|
|
||||||
object.UpdateLdapSyncTime(ldapId)
|
object.UpdateLdapSyncTime(ldapId)
|
||||||
|
|
||||||
exist, failed := object.SyncLdapUsers(owner, users, ldapId)
|
exist, failed, _ := object.SyncLdapUsers(owner, users, ldapId)
|
||||||
|
|
||||||
c.ResponseOk(&LdapSyncResp{
|
c.ResponseOk(&LdapSyncResp{
|
||||||
Exist: *exist,
|
Exist: exist,
|
||||||
Failed: *failed,
|
Failed: failed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,11 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
|
"github.com/casdoor/casdoor/ai"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
@@ -38,7 +41,7 @@ func (c *ApiController) GetMessages() {
|
|||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
chat := c.Input().Get("chat")
|
chat := c.Input().Get("chat")
|
||||||
|
organization := c.Input().Get("organization")
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
var messages []*object.Message
|
var messages []*object.Message
|
||||||
if chat == "" {
|
if chat == "" {
|
||||||
@@ -51,8 +54,8 @@ func (c *ApiController) GetMessages() {
|
|||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetMessageCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetMessageCount(owner, organization, field, value)))
|
||||||
messages := object.GetMaskedMessages(object.GetPaginationMessages(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
messages := object.GetMaskedMessages(object.GetPaginationMessages(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
||||||
c.ResponseOk(messages, paginator.Nums())
|
c.ResponseOk(messages, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,6 +74,100 @@ func (c *ApiController) GetMessage() {
|
|||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) ResponseErrorStream(errorText string) {
|
||||||
|
event := fmt.Sprintf("event: myerror\ndata: %s\n\n", errorText)
|
||||||
|
_, err := c.Ctx.ResponseWriter.Write([]byte(event))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageAnswer
|
||||||
|
// @Title GetMessageAnswer
|
||||||
|
// @Tag Message API
|
||||||
|
// @Description get message answer
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the message"
|
||||||
|
// @Success 200 {object} object.Message The Response object
|
||||||
|
// @router /get-message-answer [get]
|
||||||
|
func (c *ApiController) GetMessageAnswer() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
|
||||||
|
|
||||||
|
message := object.GetMessage(id)
|
||||||
|
if message == nil {
|
||||||
|
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.Author != "AI" || message.ReplyTo == "" || message.Text != "" {
|
||||||
|
c.ResponseErrorStream(c.T("chat:The message is invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chatId := util.GetId("admin", message.Chat)
|
||||||
|
chat := object.GetChat(chatId)
|
||||||
|
if chat == nil || chat.Organization != message.Organization {
|
||||||
|
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if chat.Type != "AI" {
|
||||||
|
c.ResponseErrorStream(c.T("chat:The chat type must be \"AI\""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
questionMessage := object.GetMessage(message.ReplyTo)
|
||||||
|
if questionMessage == nil {
|
||||||
|
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The message: %s is not found"), id))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
providerId := util.GetId(chat.Owner, chat.User2)
|
||||||
|
provider := object.GetProvider(providerId)
|
||||||
|
if provider == nil {
|
||||||
|
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is not found"), providerId))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.Category != "AI" || provider.ClientSecret == "" {
|
||||||
|
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The provider: %s is invalid"), providerId))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
|
||||||
|
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
|
||||||
|
|
||||||
|
authToken := provider.ClientSecret
|
||||||
|
question := questionMessage.Text
|
||||||
|
var stringBuilder strings.Builder
|
||||||
|
|
||||||
|
fmt.Printf("Question: [%s]\n", questionMessage.Text)
|
||||||
|
fmt.Printf("Answer: [")
|
||||||
|
|
||||||
|
err := ai.QueryAnswerStream(authToken, question, c.Ctx.ResponseWriter, &stringBuilder)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseErrorStream(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("]\n")
|
||||||
|
|
||||||
|
event := fmt.Sprintf("event: end\ndata: %s\n\n", "end")
|
||||||
|
_, err = c.Ctx.ResponseWriter.Write([]byte(event))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
answer := stringBuilder.String()
|
||||||
|
|
||||||
|
message.Text = answer
|
||||||
|
object.UpdateMessage(message.GetId(), message)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateMessage
|
// UpdateMessage
|
||||||
// @Title UpdateMessage
|
// @Title UpdateMessage
|
||||||
// @Tag Message API
|
// @Tag Message API
|
||||||
@@ -108,7 +205,34 @@ func (c *ApiController) AddMessage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.AddMessage(&message))
|
var chat *object.Chat
|
||||||
|
if message.Chat != "" {
|
||||||
|
chatId := util.GetId("admin", message.Chat)
|
||||||
|
chat = object.GetChat(chatId)
|
||||||
|
if chat == nil || chat.Organization != message.Organization {
|
||||||
|
c.ResponseError(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := object.AddMessage(&message)
|
||||||
|
if affected {
|
||||||
|
if chat != nil && chat.Type == "AI" {
|
||||||
|
answerMessage := &object.Message{
|
||||||
|
Owner: message.Owner,
|
||||||
|
Name: fmt.Sprintf("message_%s", util.GetRandomName()),
|
||||||
|
CreatedTime: util.GetCurrentTimeEx(message.CreatedTime),
|
||||||
|
Organization: message.Organization,
|
||||||
|
Chat: message.Chat,
|
||||||
|
ReplyTo: message.GetId(),
|
||||||
|
Author: "AI",
|
||||||
|
Text: "",
|
||||||
|
}
|
||||||
|
object.AddMessage(answerMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(affected)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
194
controllers/mfa.go
Normal file
194
controllers/mfa.go
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
// Copyright 2023 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 (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/beego/beego"
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MfaSetupInitiate
|
||||||
|
// @Title MfaSetupInitiate
|
||||||
|
// @Tag MFA API
|
||||||
|
// @Description setup MFA
|
||||||
|
// @param owner form string true "owner of user"
|
||||||
|
// @param name form string true "name of user"
|
||||||
|
// @param type form string true "MFA auth type"
|
||||||
|
// @Success 200 {object} The Response object
|
||||||
|
// @router /mfa/setup/initiate [post]
|
||||||
|
func (c *ApiController) MfaSetupInitiate() {
|
||||||
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
|
authType := c.Ctx.Request.Form.Get("type")
|
||||||
|
userId := util.GetId(owner, name)
|
||||||
|
|
||||||
|
if len(userId) == 0 {
|
||||||
|
c.ResponseError(http.StatusText(http.StatusBadRequest))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
MfaUtil := object.GetMfaUtil(authType, nil)
|
||||||
|
if MfaUtil == nil {
|
||||||
|
c.ResponseError("Invalid auth type")
|
||||||
|
}
|
||||||
|
user := object.GetUser(userId)
|
||||||
|
if user == nil {
|
||||||
|
c.ResponseError("User doesn't exist")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
issuer := beego.AppConfig.String("appname")
|
||||||
|
accountName := user.GetId()
|
||||||
|
|
||||||
|
mfaProps, err := MfaUtil.Initiate(c.Ctx, issuer, accountName)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := mfaProps
|
||||||
|
c.ResponseOk(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MfaSetupVerify
|
||||||
|
// @Title MfaSetupVerify
|
||||||
|
// @Tag MFA API
|
||||||
|
// @Description setup verify totp
|
||||||
|
// @param secret form string true "MFA secret"
|
||||||
|
// @param passcode form string true "MFA passcode"
|
||||||
|
// @Success 200 {object} Response object
|
||||||
|
// @router /mfa/setup/verify [post]
|
||||||
|
func (c *ApiController) MfaSetupVerify() {
|
||||||
|
authType := c.Ctx.Request.Form.Get("type")
|
||||||
|
passcode := c.Ctx.Request.Form.Get("passcode")
|
||||||
|
|
||||||
|
if authType == "" || passcode == "" {
|
||||||
|
c.ResponseError("missing auth type or passcode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
MfaUtil := object.GetMfaUtil(authType, nil)
|
||||||
|
|
||||||
|
err := MfaUtil.SetupVerify(c.Ctx, passcode)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
} else {
|
||||||
|
c.ResponseOk(http.StatusText(http.StatusOK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MfaSetupEnable
|
||||||
|
// @Title MfaSetupEnable
|
||||||
|
// @Tag MFA API
|
||||||
|
// @Description enable totp
|
||||||
|
// @param owner form string true "owner of user"
|
||||||
|
// @param name form string true "name of user"
|
||||||
|
// @param type form string true "MFA auth type"
|
||||||
|
// @Success 200 {object} Response object
|
||||||
|
// @router /mfa/setup/enable [post]
|
||||||
|
func (c *ApiController) MfaSetupEnable() {
|
||||||
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
|
authType := c.Ctx.Request.Form.Get("type")
|
||||||
|
|
||||||
|
user := object.GetUser(util.GetId(owner, name))
|
||||||
|
if user == nil {
|
||||||
|
c.ResponseError("User doesn't exist")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
twoFactor := object.GetMfaUtil(authType, nil)
|
||||||
|
err := twoFactor.Enable(c.Ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(http.StatusText(http.StatusOK))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMfa
|
||||||
|
// @Title DeleteMfa
|
||||||
|
// @Tag MFA API
|
||||||
|
// @Description: Delete MFA
|
||||||
|
// @param owner form string true "owner of user"
|
||||||
|
// @param name form string true "name of user"
|
||||||
|
// @param id form string true "id of user's MFA props"
|
||||||
|
// @Success 200 {object} Response object
|
||||||
|
// @router /delete-mfa/ [post]
|
||||||
|
func (c *ApiController) DeleteMfa() {
|
||||||
|
id := c.Ctx.Request.Form.Get("id")
|
||||||
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
|
userId := util.GetId(owner, name)
|
||||||
|
|
||||||
|
user := object.GetUser(userId)
|
||||||
|
if user == nil {
|
||||||
|
c.ResponseError("User doesn't exist")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaProps := user.MultiFactorAuths[:0]
|
||||||
|
i := 0
|
||||||
|
for _, mfaProp := range mfaProps {
|
||||||
|
if mfaProp.Id != id {
|
||||||
|
mfaProps[i] = mfaProp
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.MultiFactorAuths = mfaProps
|
||||||
|
object.UpdateUser(userId, user, []string{"multi_factor_auths"}, user.IsAdminUser())
|
||||||
|
c.ResponseOk(user.MultiFactorAuths)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPreferredMfa
|
||||||
|
// @Title SetPreferredMfa
|
||||||
|
// @Tag MFA API
|
||||||
|
// @Description: Set specific Mfa Preferred
|
||||||
|
// @param owner form string true "owner of user"
|
||||||
|
// @param name form string true "name of user"
|
||||||
|
// @param id form string true "id of user's MFA props"
|
||||||
|
// @Success 200 {object} Response object
|
||||||
|
// @router /set-preferred-mfa [post]
|
||||||
|
func (c *ApiController) SetPreferredMfa() {
|
||||||
|
id := c.Ctx.Request.Form.Get("id")
|
||||||
|
owner := c.Ctx.Request.Form.Get("owner")
|
||||||
|
name := c.Ctx.Request.Form.Get("name")
|
||||||
|
userId := util.GetId(owner, name)
|
||||||
|
|
||||||
|
user := object.GetUser(userId)
|
||||||
|
if user == nil {
|
||||||
|
c.ResponseError("User doesn't exist")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaProps := user.MultiFactorAuths
|
||||||
|
for i, mfaProp := range user.MultiFactorAuths {
|
||||||
|
if mfaProp.Id == id {
|
||||||
|
mfaProps[i].IsPreferred = true
|
||||||
|
} else {
|
||||||
|
mfaProps[i].IsPreferred = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object.UpdateUser(userId, user, []string{"multi_factor_auths"}, user.IsAdminUser())
|
||||||
|
|
||||||
|
for i, mfaProp := range mfaProps {
|
||||||
|
mfaProps[i] = object.GetMaskedProps(mfaProp)
|
||||||
|
}
|
||||||
|
c.ResponseOk(mfaProps)
|
||||||
|
}
|
@@ -148,3 +148,16 @@ func (c *ApiController) GetDefaultApplication() {
|
|||||||
maskedApplication := object.GetMaskedApplication(application, userId)
|
maskedApplication := object.GetMaskedApplication(application, userId)
|
||||||
c.ResponseOk(maskedApplication)
|
c.ResponseOk(maskedApplication)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrganizationNames ...
|
||||||
|
// @Title GetOrganizationNames
|
||||||
|
// @Tag Organization API
|
||||||
|
// @Param owner query string true "owner"
|
||||||
|
// @Description get all organization names
|
||||||
|
// @Success 200 {array} object.Organization The Response object
|
||||||
|
// @router /get-organization-names [get]
|
||||||
|
func (c *ApiController) GetOrganizationNames() {
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
organizationNames := object.GetOrganizationsByFields(owner, "name")
|
||||||
|
c.ResponseOk(organizationNames)
|
||||||
|
}
|
||||||
|
@@ -16,7 +16,6 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@@ -156,15 +155,15 @@ func (c *ApiController) NotifyPayment() {
|
|||||||
|
|
||||||
body := c.Ctx.Input.RequestBody
|
body := c.Ctx.Input.RequestBody
|
||||||
|
|
||||||
ok := object.NotifyPayment(c.Ctx.Request, body, owner, providerName, productName, paymentName)
|
err, errorResponse := object.NotifyPayment(c.Ctx.Request, body, owner, providerName, productName, paymentName)
|
||||||
if ok {
|
|
||||||
_, err := c.Ctx.ResponseWriter.Write([]byte("success"))
|
_, err2 := c.Ctx.ResponseWriter.Write([]byte(errorResponse))
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
c.ResponseError(err.Error())
|
panic(err2)
|
||||||
return
|
}
|
||||||
}
|
|
||||||
} else {
|
if err != nil {
|
||||||
panic(fmt.Errorf("NotifyPayment() failed: %v", ok))
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
137
controllers/plan.go
Normal file
137
controllers/plan.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPlans
|
||||||
|
// @Title GetPlans
|
||||||
|
// @Tag Plan API
|
||||||
|
// @Description get plans
|
||||||
|
// @Param owner query string true "The owner of plans"
|
||||||
|
// @Success 200 {array} object.Plan The Response object
|
||||||
|
// @router /get-plans [get]
|
||||||
|
func (c *ApiController) GetPlans() {
|
||||||
|
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.GetPlans(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetPlanCount(owner, field, value)))
|
||||||
|
plan := object.GetPaginatedPlans(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
c.ResponseOk(plan, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlan
|
||||||
|
// @Title GetPlan
|
||||||
|
// @Tag Plan API
|
||||||
|
// @Description get plan
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the plan"
|
||||||
|
// @Param includeOption query bool false "Should include plan's option"
|
||||||
|
// @Success 200 {object} object.Plan The Response object
|
||||||
|
// @router /get-plan [get]
|
||||||
|
func (c *ApiController) GetPlan() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
includeOption := c.Input().Get("includeOption") == "true"
|
||||||
|
|
||||||
|
plan := object.GetPlan(id)
|
||||||
|
|
||||||
|
if includeOption {
|
||||||
|
options := object.GetPermissionsByRole(plan.Role)
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
plan.Options = append(plan.Options, option.DisplayName)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = plan
|
||||||
|
} else {
|
||||||
|
c.Data["json"] = plan
|
||||||
|
}
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePlan
|
||||||
|
// @Title UpdatePlan
|
||||||
|
// @Tag Plan API
|
||||||
|
// @Description update plan
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the plan"
|
||||||
|
// @Param body body object.Plan true "The details of the plan"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /update-plan [post]
|
||||||
|
func (c *ApiController) UpdatePlan() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var plan object.Plan
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.UpdatePlan(id, &plan))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPlan
|
||||||
|
// @Title AddPlan
|
||||||
|
// @Tag Plan API
|
||||||
|
// @Description add plan
|
||||||
|
// @Param body body object.Plan true "The details of the plan"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /add-plan [post]
|
||||||
|
func (c *ApiController) AddPlan() {
|
||||||
|
var plan object.Plan
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddPlan(&plan))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePlan
|
||||||
|
// @Title DeletePlan
|
||||||
|
// @Tag Plan API
|
||||||
|
// @Description delete plan
|
||||||
|
// @Param body body object.Plan true "The details of the plan"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /delete-plan [post]
|
||||||
|
func (c *ApiController) DeletePlan() {
|
||||||
|
var plan object.Plan
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.DeletePlan(&plan))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
125
controllers/pricing.go
Normal file
125
controllers/pricing.go
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPricings
|
||||||
|
// @Title GetPricings
|
||||||
|
// @Tag Pricing API
|
||||||
|
// @Description get pricings
|
||||||
|
// @Param owner query string true "The owner of pricings"
|
||||||
|
// @Success 200 {array} object.Pricing The Response object
|
||||||
|
// @router /get-pricings [get]
|
||||||
|
func (c *ApiController) GetPricings() {
|
||||||
|
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.GetPricings(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetPricingCount(owner, field, value)))
|
||||||
|
pricing := object.GetPaginatedPricings(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
c.ResponseOk(pricing, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPricing
|
||||||
|
// @Title GetPricing
|
||||||
|
// @Tag Pricing API
|
||||||
|
// @Description get pricing
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the pricing"
|
||||||
|
// @Success 200 {object} object.pricing The Response object
|
||||||
|
// @router /get-pricing [get]
|
||||||
|
func (c *ApiController) GetPricing() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
pricing := object.GetPricing(id)
|
||||||
|
|
||||||
|
c.Data["json"] = pricing
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePricing
|
||||||
|
// @Title UpdatePricing
|
||||||
|
// @Tag Pricing API
|
||||||
|
// @Description update pricing
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the pricing"
|
||||||
|
// @Param body body object.Pricing true "The details of the pricing"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /update-pricing [post]
|
||||||
|
func (c *ApiController) UpdatePricing() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var pricing object.Pricing
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &pricing)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.UpdatePricing(id, &pricing))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPricing
|
||||||
|
// @Title AddPricing
|
||||||
|
// @Tag Pricing API
|
||||||
|
// @Description add pricing
|
||||||
|
// @Param body body object.Pricing true "The details of the pricing"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /add-pricing [post]
|
||||||
|
func (c *ApiController) AddPricing() {
|
||||||
|
var pricing object.Pricing
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &pricing)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddPricing(&pricing))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePricing
|
||||||
|
// @Title DeletePricing
|
||||||
|
// @Tag Pricing API
|
||||||
|
// @Description delete pricing
|
||||||
|
// @Param body body object.Pricing true "The details of the pricing"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /delete-pricing [post]
|
||||||
|
func (c *ApiController) DeletePricing() {
|
||||||
|
var pricing object.Pricing
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &pricing)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.DeletePricing(&pricing))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
39
controllers/prometheus.go
Normal file
39
controllers/prometheus.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPrometheusInfo
|
||||||
|
// @Title GetPrometheusInfo
|
||||||
|
// @Tag Prometheus API
|
||||||
|
// @Description get Prometheus Info
|
||||||
|
// @Success 200 {object} object.PrometheusInfo The Response object
|
||||||
|
// @router /get-prometheus-info [get]
|
||||||
|
func (c *ApiController) GetPrometheusInfo() {
|
||||||
|
_, ok := c.RequireAdmin()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prometheusInfo, err := object.GetPrometheusInfo()
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(prometheusInfo)
|
||||||
|
}
|
@@ -37,13 +37,19 @@ func (c *ApiController) GetProviders() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
|
||||||
|
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
c.Data["json"] = object.GetMaskedProviders(object.GetProviders(owner))
|
c.Data["json"] = object.GetMaskedProviders(object.GetProviders(owner), isMaskEnabled)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetProviderCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetProviderCount(owner, field, value)))
|
||||||
providers := object.GetMaskedProviders(object.GetPaginationProviders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
|
providers := object.GetMaskedProviders(object.GetPaginationProviders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder), isMaskEnabled)
|
||||||
c.ResponseOk(providers, paginator.Nums())
|
c.ResponseOk(providers, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,13 +67,19 @@ func (c *ApiController) GetGlobalProviders() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
|
||||||
|
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
c.Data["json"] = object.GetMaskedProviders(object.GetGlobalProviders())
|
c.Data["json"] = object.GetMaskedProviders(object.GetGlobalProviders(), isMaskEnabled)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalProviderCount(field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalProviderCount(field, value)))
|
||||||
providers := object.GetMaskedProviders(object.GetPaginationGlobalProviders(paginator.Offset(), limit, field, value, sortField, sortOrder))
|
providers := object.GetMaskedProviders(object.GetPaginationGlobalProviders(paginator.Offset(), limit, field, value, sortField, sortOrder), isMaskEnabled)
|
||||||
c.ResponseOk(providers, paginator.Nums())
|
c.ResponseOk(providers, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +93,13 @@ func (c *ApiController) GetGlobalProviders() {
|
|||||||
// @router /get-provider [get]
|
// @router /get-provider [get]
|
||||||
func (c *ApiController) GetProvider() {
|
func (c *ApiController) GetProvider() {
|
||||||
id := c.Input().Get("id")
|
id := c.Input().Get("id")
|
||||||
c.Data["json"] = object.GetMaskedProvider(object.GetProvider(id))
|
|
||||||
|
ok, isMaskEnabled := c.IsMaskedEnabled()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = object.GetMaskedProvider(object.GetProvider(id), isMaskEnabled)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/beego/beego/utils/pagination"
|
"github.com/beego/beego/utils/pagination"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@@ -235,10 +236,21 @@ func (c *ApiController) UploadResource() {
|
|||||||
user.Avatar = fileUrl
|
user.Avatar = fileUrl
|
||||||
object.UpdateUser(user.GetId(), user, []string{"avatar"}, false)
|
object.UpdateUser(user.GetId(), user, []string{"avatar"}, false)
|
||||||
case "termsOfUse":
|
case "termsOfUse":
|
||||||
applicationId := fmt.Sprintf("admin/%s", parent)
|
user := object.GetUserNoCheck(util.GetId(owner, username))
|
||||||
app := object.GetApplication(applicationId)
|
if user == nil {
|
||||||
app.TermsOfUse = fileUrl
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(owner, username)))
|
||||||
object.UpdateApplication(applicationId, app)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.IsAdminUser() {
|
||||||
|
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, applicationId := util.GetOwnerAndNameFromIdNoCheck(strings.TrimRight(fullFilePath, ".html"))
|
||||||
|
applicationObj := object.GetApplication(applicationId)
|
||||||
|
applicationObj.TermsOfUse = fileUrl
|
||||||
|
object.UpdateApplication(applicationId, applicationObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ResponseOk(fileUrl, objectKey)
|
c.ResponseOk(fileUrl, objectKey)
|
||||||
|
125
controllers/subscription.go
Normal file
125
controllers/subscription.go
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSubscriptions
|
||||||
|
// @Title GetSubscriptions
|
||||||
|
// @Tag Subscription API
|
||||||
|
// @Description get subscriptions
|
||||||
|
// @Param owner query string true "The owner of subscriptions"
|
||||||
|
// @Success 200 {array} object.Subscription The Response object
|
||||||
|
// @router /get-subscriptions [get]
|
||||||
|
func (c *ApiController) GetSubscriptions() {
|
||||||
|
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.GetSubscriptions(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
} else {
|
||||||
|
limit := util.ParseInt(limit)
|
||||||
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSubscriptionCount(owner, field, value)))
|
||||||
|
subscription := object.GetPaginationSubscriptions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
|
c.ResponseOk(subscription, paginator.Nums())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubscription
|
||||||
|
// @Title GetSubscription
|
||||||
|
// @Tag Subscription API
|
||||||
|
// @Description get subscription
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the subscription"
|
||||||
|
// @Success 200 {object} object.subscription The Response object
|
||||||
|
// @router /get-subscription [get]
|
||||||
|
func (c *ApiController) GetSubscription() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
subscription := object.GetSubscription(id)
|
||||||
|
|
||||||
|
c.Data["json"] = subscription
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSubscription
|
||||||
|
// @Title UpdateSubscription
|
||||||
|
// @Tag Subscription API
|
||||||
|
// @Description update subscription
|
||||||
|
// @Param id query string true "The id ( owner/name ) of the subscription"
|
||||||
|
// @Param body body object.Subscription true "The details of the subscription"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /update-subscription [post]
|
||||||
|
func (c *ApiController) UpdateSubscription() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var subscription object.Subscription
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &subscription)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.UpdateSubscription(id, &subscription))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSubscription
|
||||||
|
// @Title AddSubscription
|
||||||
|
// @Tag Subscription API
|
||||||
|
// @Description add subscription
|
||||||
|
// @Param body body object.Subscription true "The details of the subscription"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /add-subscription [post]
|
||||||
|
func (c *ApiController) AddSubscription() {
|
||||||
|
var subscription object.Subscription
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &subscription)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.AddSubscription(&subscription))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSubscription
|
||||||
|
// @Title DeleteSubscription
|
||||||
|
// @Tag Subscription API
|
||||||
|
// @Description delete subscription
|
||||||
|
// @Param body body object.Subscription true "The details of the subscription"
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /delete-subscription [post]
|
||||||
|
func (c *ApiController) DeleteSubscription() {
|
||||||
|
var subscription object.Subscription
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &subscription)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = wrapActionResponse(object.DeleteSubscription(&subscription))
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
@@ -37,13 +37,14 @@ func (c *ApiController) GetSyncers() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
organization := c.Input().Get("organization")
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
c.Data["json"] = object.GetSyncers(owner)
|
c.Data["json"] = object.GetOrganizationSyncers(owner, organization)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner, organization, field, value)))
|
||||||
syncers := object.GetPaginationSyncers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
syncers := object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
c.ResponseOk(syncers, paginator.Nums())
|
c.ResponseOk(syncers, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,3 +59,13 @@ func (c *ApiController) GetVersionInfo() {
|
|||||||
|
|
||||||
c.ResponseOk(versionInfo)
|
c.ResponseOk(versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Health
|
||||||
|
// @Title Health
|
||||||
|
// @Tag System API
|
||||||
|
// @Description check if the system is live
|
||||||
|
// @Success 200 {object} controllers.Response The Response object
|
||||||
|
// @router /health [get]
|
||||||
|
func (c *ApiController) Health() {
|
||||||
|
c.ResponseOk()
|
||||||
|
}
|
||||||
|
@@ -39,13 +39,14 @@ func (c *ApiController) GetTokens() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
organization := c.Input().Get("organization")
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
c.Data["json"] = object.GetTokens(owner)
|
c.Data["json"] = object.GetTokens(owner, organization)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner, organization, field, value)))
|
||||||
tokens := object.GetPaginationTokens(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
tokens := object.GetPaginationTokens(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
c.ResponseOk(tokens, paginator.Nums())
|
c.ResponseOk(tokens, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
|
|||||||
// @Title GetUser
|
// @Title GetUser
|
||||||
// @Tag User API
|
// @Tag User API
|
||||||
// @Description get user
|
// @Description get user
|
||||||
// @Param id query string true "The id ( owner/name ) of the user"
|
// @Param id query string false "The id ( owner/name ) of the user"
|
||||||
// @Param owner query string false "The owner of the user"
|
// @Param owner query string false "The owner of the user"
|
||||||
// @Param email query string false "The email of the user"
|
// @Param email query string false "The email of the user"
|
||||||
// @Param phone query string false "The phone of the user"
|
// @Param phone query string false "The phone of the user"
|
||||||
@@ -92,13 +92,19 @@ func (c *ApiController) GetUser() {
|
|||||||
email := c.Input().Get("email")
|
email := c.Input().Get("email")
|
||||||
phone := c.Input().Get("phone")
|
phone := c.Input().Get("phone")
|
||||||
userId := c.Input().Get("userId")
|
userId := c.Input().Get("userId")
|
||||||
|
|
||||||
owner := c.Input().Get("owner")
|
owner := c.Input().Get("owner")
|
||||||
|
|
||||||
|
var userFromUserId *object.User
|
||||||
|
if userId != "" && owner != "" {
|
||||||
|
userFromUserId = object.GetUserByUserId(owner, userId)
|
||||||
|
id = util.GetId(userFromUserId.Owner, userFromUserId.Name)
|
||||||
|
}
|
||||||
|
|
||||||
if owner == "" {
|
if owner == "" {
|
||||||
owner = util.GetOwnerFromId(id)
|
owner = util.GetOwnerFromId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", owner))
|
organization := object.GetOrganization(util.GetId("admin", owner))
|
||||||
if !organization.IsProfilePublic {
|
if !organization.IsProfilePublic {
|
||||||
requestUserId := c.GetSessionUsername()
|
requestUserId := c.GetSessionUsername()
|
||||||
hasPermission, err := object.CheckUserPermission(requestUserId, id, false, c.GetAcceptLanguage())
|
hasPermission, err := object.CheckUserPermission(requestUserId, id, false, c.GetAcceptLanguage())
|
||||||
@@ -115,7 +121,7 @@ func (c *ApiController) GetUser() {
|
|||||||
case phone != "":
|
case phone != "":
|
||||||
user = object.GetUserByPhone(owner, phone)
|
user = object.GetUserByPhone(owner, phone)
|
||||||
case userId != "":
|
case userId != "":
|
||||||
user = object.GetUserByUserId(owner, userId)
|
user = userFromUserId
|
||||||
default:
|
default:
|
||||||
user = object.GetUser(id)
|
user = object.GetUser(id)
|
||||||
}
|
}
|
||||||
@@ -158,11 +164,18 @@ func (c *ApiController) UpdateUser() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if oldUser.Owner == "built-in" && oldUser.Name == "admin" && (user.Owner != "built-in" || user.Name != "admin") {
|
||||||
|
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
|
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
|
||||||
c.ResponseError(msg)
|
c.ResponseError(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if pass, err := checkPermissionForUpdateUser(oldUser, &user, c); !pass {
|
|
||||||
|
isAdmin := c.IsAdmin()
|
||||||
|
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, c.GetAcceptLanguage()); !pass {
|
||||||
c.ResponseError(err)
|
c.ResponseError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -172,9 +185,7 @@ func (c *ApiController) UpdateUser() {
|
|||||||
columns = strings.Split(columnsStr, ",")
|
columns = strings.Split(columnsStr, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
isGlobalAdmin := c.IsGlobalAdmin()
|
affected := object.UpdateUser(id, &user, columns, isAdmin)
|
||||||
|
|
||||||
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
|
|
||||||
if affected {
|
if affected {
|
||||||
object.UpdateUserToOriginalDatabase(&user)
|
object.UpdateUserToOriginalDatabase(&user)
|
||||||
}
|
}
|
||||||
@@ -229,6 +240,11 @@ func (c *ApiController) DeleteUser() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.Owner == "built-in" && user.Name == "admin" {
|
||||||
|
c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
|
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
@@ -286,6 +302,11 @@ func (c *ApiController) SetPassword() {
|
|||||||
newPassword := c.Ctx.Request.Form.Get("newPassword")
|
newPassword := c.Ctx.Request.Form.Get("newPassword")
|
||||||
code := c.Ctx.Request.Form.Get("code")
|
code := c.Ctx.Request.Form.Get("code")
|
||||||
|
|
||||||
|
//if userOwner == "built-in" && userName == "admin" {
|
||||||
|
// c.ResponseError(c.T("auth:Unauthorized operation"))
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
if strings.Contains(newPassword, " ") {
|
if strings.Contains(newPassword, " ") {
|
||||||
c.ResponseError(c.T("user:New password cannot contain blank space."))
|
c.ResponseError(c.T("user:New password cannot contain blank space."))
|
||||||
return
|
return
|
||||||
|
@@ -1,138 +0,0 @@
|
|||||||
// Copyright 2023 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/casdoor/casdoor/object"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkPermissionForUpdateUser(oldUser, newUser *object.User, c *ApiController) (bool, string) {
|
|
||||||
organization := object.GetOrganizationByUser(oldUser)
|
|
||||||
var itemsChanged []*object.AccountItem
|
|
||||||
|
|
||||||
if oldUser.Owner != newUser.Owner {
|
|
||||||
item := object.GetAccountItemByName("Organization", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Name != newUser.Name {
|
|
||||||
item := object.GetAccountItemByName("Name", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Id != newUser.Id {
|
|
||||||
item := object.GetAccountItemByName("ID", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.DisplayName != newUser.DisplayName {
|
|
||||||
item := object.GetAccountItemByName("Display name", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Avatar != newUser.Avatar {
|
|
||||||
item := object.GetAccountItemByName("Avatar", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Type != newUser.Type {
|
|
||||||
item := object.GetAccountItemByName("User type", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
// The password is *** when not modified
|
|
||||||
if oldUser.Password != newUser.Password && newUser.Password != "***" {
|
|
||||||
item := object.GetAccountItemByName("Password", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Email != newUser.Email {
|
|
||||||
item := object.GetAccountItemByName("Email", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Phone != newUser.Phone {
|
|
||||||
item := object.GetAccountItemByName("Phone", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.CountryCode != newUser.CountryCode {
|
|
||||||
item := object.GetAccountItemByName("Country code", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Region != newUser.Region {
|
|
||||||
item := object.GetAccountItemByName("Country/Region", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Location != newUser.Location {
|
|
||||||
item := object.GetAccountItemByName("Location", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Affiliation != newUser.Affiliation {
|
|
||||||
item := object.GetAccountItemByName("Affiliation", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Title != newUser.Title {
|
|
||||||
item := object.GetAccountItemByName("Title", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Homepage != newUser.Homepage {
|
|
||||||
item := object.GetAccountItemByName("Homepage", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Bio != newUser.Bio {
|
|
||||||
item := object.GetAccountItemByName("Bio", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.Tag != newUser.Tag {
|
|
||||||
item := object.GetAccountItemByName("Tag", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.SignupApplication != newUser.SignupApplication {
|
|
||||||
item := object.GetAccountItemByName("Signup application", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldUserPropertiesJson, _ := json.Marshal(oldUser.Properties)
|
|
||||||
newUserPropertiesJson, _ := json.Marshal(newUser.Properties)
|
|
||||||
if string(oldUserPropertiesJson) != string(newUserPropertiesJson) {
|
|
||||||
item := object.GetAccountItemByName("Properties", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldUser.IsAdmin != newUser.IsAdmin {
|
|
||||||
item := object.GetAccountItemByName("Is admin", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
|
|
||||||
item := object.GetAccountItemByName("Is global admin", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.IsForbidden != newUser.IsForbidden {
|
|
||||||
item := object.GetAccountItemByName("Is forbidden", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
if oldUser.IsDeleted != newUser.IsDeleted {
|
|
||||||
item := object.GetAccountItemByName("Is deleted", organization)
|
|
||||||
itemsChanged = append(itemsChanged, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentUser := c.getCurrentUser()
|
|
||||||
if currentUser == nil && c.IsGlobalAdmin() {
|
|
||||||
currentUser = &object.User{
|
|
||||||
IsGlobalAdmin: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range itemsChanged {
|
|
||||||
if pass, err := object.CheckAccountItemModifyRule(itemsChanged[i], currentUser, c.GetAcceptLanguage()); !pass {
|
|
||||||
return pass, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true, ""
|
|
||||||
}
|
|
@@ -16,7 +16,6 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/i18n"
|
"github.com/casdoor/casdoor/i18n"
|
||||||
@@ -115,12 +114,25 @@ func (c *ApiController) RequireAdmin() (string, bool) {
|
|||||||
return user.Owner, true
|
return user.Owner, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInitScore(organization *object.Organization) (int, error) {
|
// IsMaskedEnabled ...
|
||||||
if organization != nil {
|
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
|
||||||
return organization.InitScore, nil
|
isMaskEnabled := true
|
||||||
} else {
|
withSecret := c.Input().Get("withSecret")
|
||||||
return strconv.Atoi(conf.GetConfigString("initScore"))
|
if withSecret == "1" {
|
||||||
|
isMaskEnabled = false
|
||||||
|
|
||||||
|
if conf.IsDemoMode() {
|
||||||
|
c.ResponseError(c.T("general:this operation is not allowed in demo mode"))
|
||||||
|
return false, isMaskEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := c.RequireAdmin()
|
||||||
|
if !ok {
|
||||||
|
return false, isMaskEnabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true, isMaskEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {
|
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, *object.User, bool) {
|
||||||
@@ -128,7 +140,7 @@ func (c *ApiController) GetProviderFromContext(category string) (*object.Provide
|
|||||||
if providerName != "" {
|
if providerName != "" {
|
||||||
provider := object.GetProvider(util.GetId("admin", providerName))
|
provider := object.GetProvider(util.GetId("admin", providerName))
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
c.ResponseError(c.T("util:The provider: %s is not found"), providerName)
|
c.ResponseError(fmt.Sprintf(c.T("util:The provider: %s is not found"), providerName))
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
return provider, nil, true
|
return provider, nil, true
|
||||||
|
@@ -21,71 +21,43 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/captcha"
|
"github.com/casdoor/casdoor/captcha"
|
||||||
|
"github.com/casdoor/casdoor/form"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SignupVerification = "signup"
|
SignupVerification = "signup"
|
||||||
ResetVerification = "reset"
|
ResetVerification = "reset"
|
||||||
LoginVerification = "login"
|
LoginVerification = "login"
|
||||||
ForgetVerification = "forget"
|
ForgetVerification = "forget"
|
||||||
|
MfaSetupVerification = "mfaSetup"
|
||||||
|
MfaAuthVerification = "mfaAuth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *ApiController) getCurrentUser() *object.User {
|
|
||||||
var user *object.User
|
|
||||||
userId := c.GetSessionUsername()
|
|
||||||
if userId == "" {
|
|
||||||
user = nil
|
|
||||||
} else {
|
|
||||||
user = object.GetUser(userId)
|
|
||||||
}
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendVerificationCode ...
|
// SendVerificationCode ...
|
||||||
// @Title SendVerificationCode
|
// @Title SendVerificationCode
|
||||||
// @Tag Verification API
|
// @Tag Verification API
|
||||||
// @router /send-verification-code [post]
|
// @router /send-verification-code [post]
|
||||||
func (c *ApiController) SendVerificationCode() {
|
func (c *ApiController) SendVerificationCode() {
|
||||||
destType := c.Ctx.Request.Form.Get("type")
|
var vform form.VerificationForm
|
||||||
dest := c.Ctx.Request.Form.Get("dest")
|
err := c.ParseForm(&vform)
|
||||||
countryCode := c.Ctx.Request.Form.Get("countryCode")
|
if err != nil {
|
||||||
checkType := c.Ctx.Request.Form.Get("checkType")
|
c.ResponseError(err.Error())
|
||||||
clientSecret := c.Ctx.Request.Form.Get("clientSecret")
|
return
|
||||||
captchaToken := c.Ctx.Request.Form.Get("captchaToken")
|
}
|
||||||
applicationId := c.Ctx.Request.Form.Get("applicationId")
|
|
||||||
method := c.Ctx.Request.Form.Get("method")
|
|
||||||
checkUser := c.Ctx.Request.Form.Get("checkUser")
|
|
||||||
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
|
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
|
||||||
|
|
||||||
if dest == "" {
|
if msg := vform.CheckParameter(form.SendVerifyCode, c.GetAcceptLanguage()); msg != "" {
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": dest.")
|
c.ResponseError(msg)
|
||||||
return
|
|
||||||
}
|
|
||||||
if applicationId == "" {
|
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": applicationId.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if checkType == "" {
|
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": checkType.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !strings.Contains(applicationId, "/") {
|
|
||||||
c.ResponseError(c.T("verification:Wrong parameter") + ": applicationId.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkType != "none" {
|
if vform.CaptchaType != "none" {
|
||||||
if captchaToken == "" {
|
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": captchaToken.")
|
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
|
||||||
return
|
return
|
||||||
}
|
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret); err != nil {
|
||||||
|
|
||||||
if captchaProvider := captcha.GetCaptchaProvider(checkType); captchaProvider == nil {
|
|
||||||
c.ResponseError(c.T("general:don't support captchaProvider: ") + checkType)
|
|
||||||
return
|
|
||||||
} else if isHuman, err := captchaProvider.VerifyCaptcha(captchaToken, clientSecret); err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
} else if !isHuman {
|
} else if !isHuman {
|
||||||
@@ -94,7 +66,7 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
application := object.GetApplication(applicationId)
|
application := object.GetApplication(vform.ApplicationId)
|
||||||
organization := object.GetOrganization(util.GetId(application.Owner, application.Organization))
|
organization := object.GetOrganization(util.GetId(application.Owner, application.Organization))
|
||||||
if organization == nil {
|
if organization == nil {
|
||||||
c.ResponseError(c.T("check:Organization does not exist"))
|
c.ResponseError(c.T("check:Organization does not exist"))
|
||||||
@@ -103,63 +75,85 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
|
|
||||||
var user *object.User
|
var user *object.User
|
||||||
// checkUser != "", means method is ForgetVerification
|
// checkUser != "", means method is ForgetVerification
|
||||||
if checkUser != "" {
|
if vform.CheckUser != "" {
|
||||||
owner := application.Organization
|
owner := application.Organization
|
||||||
user = object.GetUser(util.GetId(owner, checkUser))
|
user = object.GetUser(util.GetId(owner, vform.CheckUser))
|
||||||
|
}
|
||||||
|
|
||||||
|
// mfaSessionData != nil, means method is MfaSetupVerification
|
||||||
|
if mfaSessionData := c.getMfaSessionData(); mfaSessionData != nil {
|
||||||
|
user = object.GetUser(mfaSessionData.UserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResp := errors.New("invalid dest type")
|
sendResp := errors.New("invalid dest type")
|
||||||
|
|
||||||
switch destType {
|
switch vform.Type {
|
||||||
case object.VerifyTypeEmail:
|
case object.VerifyTypeEmail:
|
||||||
if !util.IsEmailValid(dest) {
|
if !util.IsEmailValid(vform.Dest) {
|
||||||
c.ResponseError(c.T("check:Email is invalid"))
|
c.ResponseError(c.T("check:Email is invalid"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if method == LoginVerification || method == ForgetVerification {
|
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
|
||||||
if user != nil && util.GetMaskedEmail(user.Email) == dest {
|
if user != nil && util.GetMaskedEmail(user.Email) == vform.Dest {
|
||||||
dest = user.Email
|
vform.Dest = user.Email
|
||||||
}
|
}
|
||||||
|
|
||||||
user = object.GetUserByEmail(organization.Name, dest)
|
user = object.GetUserByEmail(organization.Name, vform.Dest)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
|
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if method == ResetVerification {
|
} else if vform.Method == ResetVerification {
|
||||||
user = c.getCurrentUser()
|
user = c.getCurrentUser()
|
||||||
|
} else if vform.Method == MfaAuthVerification {
|
||||||
|
mfaProps := user.GetPreferMfa(false)
|
||||||
|
if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest {
|
||||||
|
vform.Dest = mfaProps.Secret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := application.GetEmailProvider()
|
provider := application.GetEmailProvider()
|
||||||
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, dest)
|
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, vform.Dest)
|
||||||
case object.VerifyTypePhone:
|
case object.VerifyTypePhone:
|
||||||
if method == LoginVerification || method == ForgetVerification {
|
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
|
||||||
if user != nil && util.GetMaskedPhone(user.Phone) == dest {
|
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
|
||||||
dest = user.Phone
|
vform.Dest = user.Phone
|
||||||
}
|
}
|
||||||
|
|
||||||
if user = object.GetUserByPhone(organization.Name, dest); user == nil {
|
if user = object.GetUserByPhone(organization.Name, vform.Dest); user == nil {
|
||||||
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
|
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
countryCode = user.GetCountryCode(countryCode)
|
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
|
||||||
} else if method == ResetVerification {
|
} else if vform.Method == ResetVerification {
|
||||||
if user = c.getCurrentUser(); user != nil {
|
if user = c.getCurrentUser(); user != nil {
|
||||||
countryCode = user.GetCountryCode(countryCode)
|
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
|
||||||
}
|
}
|
||||||
|
} else if vform.Method == MfaAuthVerification {
|
||||||
|
mfaProps := user.GetPreferMfa(false)
|
||||||
|
if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest {
|
||||||
|
vform.Dest = mfaProps.Secret
|
||||||
|
}
|
||||||
|
|
||||||
|
vform.CountryCode = mfaProps.CountryCode
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := application.GetSmsProvider()
|
provider := application.GetSmsProvider()
|
||||||
if phone, ok := util.GetE164Number(dest, countryCode); !ok {
|
if phone, ok := util.GetE164Number(vform.Dest, vform.CountryCode); !ok {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), countryCode))
|
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
|
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if vform.Method == MfaSetupVerification {
|
||||||
|
c.SetSession(object.MfaSmsCountryCodeSession, vform.CountryCode)
|
||||||
|
c.SetSession(object.MfaSmsDestSession, vform.Dest)
|
||||||
|
}
|
||||||
|
|
||||||
if sendResp != nil {
|
if sendResp != nil {
|
||||||
c.ResponseError(sendResp.Error())
|
c.ResponseError(sendResp.Error())
|
||||||
} else {
|
} else {
|
||||||
@@ -167,6 +161,38 @@ func (c *ApiController) SendVerificationCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyCaptcha ...
|
||||||
|
// @Title VerifyCaptcha
|
||||||
|
// @Tag Verification API
|
||||||
|
// @router /verify-captcha [post]
|
||||||
|
func (c *ApiController) VerifyCaptcha() {
|
||||||
|
var vform form.VerificationForm
|
||||||
|
err := c.ParseForm(&vform)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg := vform.CheckParameter(form.VerifyCaptcha, c.GetAcceptLanguage()); msg != "" {
|
||||||
|
c.ResponseError(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := captcha.GetCaptchaProvider(vform.CaptchaType)
|
||||||
|
if provider == nil {
|
||||||
|
c.ResponseError(c.T("verification:Invalid captcha provider."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid, err := provider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(isValid)
|
||||||
|
}
|
||||||
|
|
||||||
// ResetEmailOrPhone ...
|
// ResetEmailOrPhone ...
|
||||||
// @Tag Account API
|
// @Tag Account API
|
||||||
// @Title ResetEmailOrPhone
|
// @Title ResetEmailOrPhone
|
||||||
@@ -200,7 +226,7 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pass, errMsg := object.CheckAccountItemModifyRule(phoneItem, user, c.GetAcceptLanguage()); !pass {
|
if pass, errMsg := object.CheckAccountItemModifyRule(phoneItem, user.IsAdminUser(), c.GetAcceptLanguage()); !pass {
|
||||||
c.ResponseError(errMsg)
|
c.ResponseError(errMsg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -220,11 +246,12 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pass, errMsg := object.CheckAccountItemModifyRule(emailItem, user, c.GetAcceptLanguage()); !pass {
|
if pass, errMsg := object.CheckAccountItemModifyRule(emailItem, user.IsAdminUser(), c.GetAcceptLanguage()); !pass {
|
||||||
c.ResponseError(errMsg)
|
c.ResponseError(errMsg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
if result := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
||||||
c.ResponseError(result.Msg)
|
c.ResponseError(result.Msg)
|
||||||
return
|
return
|
||||||
@@ -247,88 +274,55 @@ func (c *ApiController) ResetEmailOrPhone() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyCode
|
// VerifyCode
|
||||||
// @Tag Account API
|
// @Tag Verification API
|
||||||
// @Title VerifyCode
|
// @Title VerifyCode
|
||||||
// @router /api/verify-code [post]
|
// @router /api/verify-code [post]
|
||||||
func (c *ApiController) VerifyCode() {
|
func (c *ApiController) VerifyCode() {
|
||||||
var form RequestForm
|
var authForm form.AuthForm
|
||||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var user *object.User
|
var user *object.User
|
||||||
if form.Name != "" {
|
if authForm.Name != "" {
|
||||||
user = object.GetUserByFields(form.Organization, form.Name)
|
user = object.GetUserByFields(authForm.Organization, authForm.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkDest string
|
var checkDest string
|
||||||
if strings.Contains(form.Username, "@") {
|
if strings.Contains(authForm.Username, "@") {
|
||||||
if user != nil && util.GetMaskedEmail(user.Email) == form.Username {
|
if user != nil && util.GetMaskedEmail(user.Email) == authForm.Username {
|
||||||
form.Username = user.Email
|
authForm.Username = user.Email
|
||||||
}
|
}
|
||||||
checkDest = form.Username
|
checkDest = authForm.Username
|
||||||
} else {
|
} else {
|
||||||
if user != nil && util.GetMaskedPhone(user.Phone) == form.Username {
|
if user != nil && util.GetMaskedPhone(user.Phone) == authForm.Username {
|
||||||
form.Username = user.Phone
|
authForm.Username = user.Phone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if user = object.GetUserByFields(form.Organization, form.Username); user == nil {
|
if user = object.GetUserByFields(authForm.Organization, authForm.Username); user == nil {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username)))
|
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(authForm.Organization, authForm.Username)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationCodeType := object.GetVerifyType(form.Username)
|
verificationCodeType := object.GetVerifyType(authForm.Username)
|
||||||
if verificationCodeType == object.VerifyTypePhone {
|
if verificationCodeType == object.VerifyTypePhone {
|
||||||
form.CountryCode = user.GetCountryCode(form.CountryCode)
|
authForm.CountryCode = user.GetCountryCode(authForm.CountryCode)
|
||||||
var ok bool
|
var ok bool
|
||||||
if checkDest, ok = util.GetE164Number(form.Username, form.CountryCode); !ok {
|
if checkDest, ok = util.GetE164Number(authForm.Username, authForm.CountryCode); !ok {
|
||||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), form.CountryCode))
|
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), authForm.CountryCode))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result := object.CheckVerificationCode(checkDest, form.Code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
if result := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
|
||||||
c.ResponseError(result.Msg)
|
c.ResponseError(result.Msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
object.DisableVerificationCode(checkDest)
|
object.DisableVerificationCode(checkDest)
|
||||||
c.SetSession("verifiedCode", form.Code)
|
c.SetSession("verifiedCode", authForm.Code)
|
||||||
|
|
||||||
c.ResponseOk()
|
c.ResponseOk()
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyCaptcha ...
|
|
||||||
// @Title VerifyCaptcha
|
|
||||||
// @Tag Verification API
|
|
||||||
// @router /verify-captcha [post]
|
|
||||||
func (c *ApiController) VerifyCaptcha() {
|
|
||||||
captchaType := c.Ctx.Request.Form.Get("captchaType")
|
|
||||||
|
|
||||||
captchaToken := c.Ctx.Request.Form.Get("captchaToken")
|
|
||||||
clientSecret := c.Ctx.Request.Form.Get("clientSecret")
|
|
||||||
if captchaToken == "" {
|
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": captchaToken.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if clientSecret == "" {
|
|
||||||
c.ResponseError(c.T("general:Missing parameter") + ": clientSecret.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
provider := captcha.GetCaptchaProvider(captchaType)
|
|
||||||
if provider == nil {
|
|
||||||
c.ResponseError(c.T("verification:Invalid captcha provider."))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isValid, err := provider.VerifyCaptcha(captchaToken, clientSecret)
|
|
||||||
if err != nil {
|
|
||||||
c.ResponseError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ResponseOk(isValid)
|
|
||||||
}
|
|
||||||
|
@@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/form"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/go-webauthn/webauthn/protocol"
|
"github.com/go-webauthn/webauthn/protocol"
|
||||||
@@ -147,9 +148,9 @@ func (c *ApiController) WebAuthnSigninFinish() {
|
|||||||
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
|
||||||
|
|
||||||
application := object.GetApplicationByUser(user)
|
application := object.GetApplicationByUser(user)
|
||||||
var form RequestForm
|
var authForm form.AuthForm
|
||||||
form.Type = responseType
|
authForm.Type = responseType
|
||||||
resp := c.HandleLoggedIn(application, user, &form)
|
resp := c.HandleLoggedIn(application, user, &authForm)
|
||||||
c.Data["json"] = resp
|
c.Data["json"] = resp
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
@@ -37,13 +37,14 @@ func (c *ApiController) GetWebhooks() {
|
|||||||
value := c.Input().Get("value")
|
value := c.Input().Get("value")
|
||||||
sortField := c.Input().Get("sortField")
|
sortField := c.Input().Get("sortField")
|
||||||
sortOrder := c.Input().Get("sortOrder")
|
sortOrder := c.Input().Get("sortOrder")
|
||||||
|
organization := c.Input().Get("organization")
|
||||||
if limit == "" || page == "" {
|
if limit == "" || page == "" {
|
||||||
c.Data["json"] = object.GetWebhooks(owner)
|
c.Data["json"] = object.GetWebhooks(owner, organization)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner, field, value)))
|
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner, organization, field, value)))
|
||||||
webhooks := object.GetPaginationWebhooks(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
webhooks := object.GetPaginationWebhooks(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
c.ResponseOk(webhooks, paginator.Nums())
|
c.ResponseOk(webhooks, paginator.Nums())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
form/auth.go
Normal file
60
form/auth.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2023 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 form
|
||||||
|
|
||||||
|
type AuthForm struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
Organization string `json:"organization"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
FirstName string `json:"firstName"`
|
||||||
|
LastName string `json:"lastName"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Affiliation string `json:"affiliation"`
|
||||||
|
IdCard string `json:"idCard"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
|
||||||
|
Application string `json:"application"`
|
||||||
|
ClientId string `json:"clientId"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
State string `json:"state"`
|
||||||
|
RedirectUri string `json:"redirectUri"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
|
||||||
|
EmailCode string `json:"emailCode"`
|
||||||
|
PhoneCode string `json:"phoneCode"`
|
||||||
|
CountryCode string `json:"countryCode"`
|
||||||
|
|
||||||
|
AutoSignin bool `json:"autoSignin"`
|
||||||
|
|
||||||
|
RelayState string `json:"relayState"`
|
||||||
|
SamlRequest string `json:"samlRequest"`
|
||||||
|
SamlResponse string `json:"samlResponse"`
|
||||||
|
|
||||||
|
CaptchaType string `json:"captchaType"`
|
||||||
|
CaptchaToken string `json:"captchaToken"`
|
||||||
|
ClientSecret string `json:"clientSecret"`
|
||||||
|
|
||||||
|
MfaType string `json:"mfaType"`
|
||||||
|
Passcode string `json:"passcode"`
|
||||||
|
RecoveryCode string `json:"recoveryCode"`
|
||||||
|
|
||||||
|
Plan string `json:"plan"`
|
||||||
|
Pricing string `json:"pricing"`
|
||||||
|
}
|
67
form/verification.go
Normal file
67
form/verification.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2023 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 form
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VerificationForm struct {
|
||||||
|
Dest string `form:"dest"`
|
||||||
|
Type string `form:"type"`
|
||||||
|
CountryCode string `form:"countryCode"`
|
||||||
|
ApplicationId string `form:"applicationId"`
|
||||||
|
Method string `form:"method"`
|
||||||
|
CheckUser string `form:"checkUser"`
|
||||||
|
|
||||||
|
CaptchaType string `form:"captchaType"`
|
||||||
|
ClientSecret string `form:"clientSecret"`
|
||||||
|
CaptchaToken string `form:"captchaToken"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SendVerifyCode = 0
|
||||||
|
VerifyCaptcha = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (form *VerificationForm) CheckParameter(checkType int, lang string) string {
|
||||||
|
if checkType == SendVerifyCode {
|
||||||
|
if form.Type == "" {
|
||||||
|
return i18n.Translate(lang, "general:Missing parameter") + ": type."
|
||||||
|
}
|
||||||
|
if form.Dest == "" {
|
||||||
|
return i18n.Translate(lang, "general:Missing parameter") + ": dest."
|
||||||
|
}
|
||||||
|
if form.CaptchaType == "" {
|
||||||
|
return i18n.Translate(lang, "general:Missing parameter") + ": checkType."
|
||||||
|
}
|
||||||
|
if !strings.Contains(form.ApplicationId, "/") {
|
||||||
|
return i18n.Translate(lang, "verification:Wrong parameter") + ": applicationId."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.CaptchaType != "none" {
|
||||||
|
if form.CaptchaToken == "" {
|
||||||
|
return i18n.Translate(lang, "general:Missing parameter") + ": captchaToken."
|
||||||
|
}
|
||||||
|
if form.ClientSecret == "" {
|
||||||
|
return i18n.Translate(lang, "general:Missing parameter") + ": clientSecret."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
25
go.mod
25
go.mod
@@ -8,8 +8,9 @@ require (
|
|||||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
|
||||||
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 // indirect
|
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 // indirect
|
||||||
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/beego/beego v1.12.12
|
||||||
github.com/beevik/etree v1.1.0
|
github.com/beevik/etree v1.1.0
|
||||||
|
github.com/casbin/casbin v1.9.1 // indirect
|
||||||
github.com/casbin/casbin/v2 v2.30.1
|
github.com/casbin/casbin/v2 v2.30.1
|
||||||
github.com/casdoor/go-sms-sender v0.6.1
|
github.com/casdoor/go-sms-sender v0.6.1
|
||||||
github.com/casdoor/gomail/v2 v2.0.1
|
github.com/casdoor/gomail/v2 v2.0.1
|
||||||
@@ -17,6 +18,8 @@ require (
|
|||||||
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
github.com/casdoor/xorm-adapter/v3 v3.0.4
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/denisenkom/go-mssqldb v0.9.0
|
github.com/denisenkom/go-mssqldb v0.9.0
|
||||||
|
github.com/dlclark/regexp2 v1.9.0 // indirect
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
||||||
github.com/fogleman/gg v1.3.0
|
github.com/fogleman/gg v1.3.0
|
||||||
github.com/forestmgy/ldapserver v1.1.0
|
github.com/forestmgy/ldapserver v1.1.0
|
||||||
github.com/go-git/go-git/v5 v5.6.0
|
github.com/go-git/go-git/v5 v5.6.0
|
||||||
@@ -27,24 +30,31 @@ require (
|
|||||||
github.com/go-webauthn/webauthn v0.6.0
|
github.com/go-webauthn/webauthn v0.6.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/gorilla/mux v1.7.3 // indirect
|
||||||
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 v1.2.21
|
github.com/lestrrat-go/jwx v1.2.21
|
||||||
github.com/lib/pq v1.8.0
|
github.com/lib/pq v1.10.2
|
||||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
|
||||||
github.com/markbates/goth v1.75.2
|
github.com/markbates/goth v1.75.2
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||||
github.com/nyaruka/phonenumbers v1.1.5
|
github.com/nyaruka/phonenumbers v1.1.5
|
||||||
|
github.com/pkoukk/tiktoken-go v0.1.1
|
||||||
|
github.com/prometheus/client_golang v1.11.1
|
||||||
|
github.com/prometheus/client_model v0.2.0
|
||||||
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.9.0
|
||||||
github.com/russellhaering/goxmldsig v1.1.1
|
github.com/russellhaering/goxmldsig v1.2.0
|
||||||
|
github.com/sashabaranov/go-openai v1.9.1
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
|
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.2
|
||||||
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/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
@@ -52,10 +62,11 @@ require (
|
|||||||
github.com/xorm-io/xorm v1.1.6
|
github.com/xorm-io/xorm v1.1.6
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.6.0
|
golang.org/x/crypto v0.6.0
|
||||||
golang.org/x/net v0.6.0
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||||
|
golang.org/x/net v0.7.0
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
|
||||||
)
|
)
|
||||||
|
82
go.sum
82
go.sum
@@ -73,6 +73,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
|||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90vF44BPW4ZYOkE3tDkGTy7yHURusOJimt+I=
|
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90vF44BPW4ZYOkE3tDkGTy7yHURusOJimt+I=
|
||||||
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
|
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
|
||||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
@@ -92,8 +93,8 @@ 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.12 h1:ARY1sNVSS23N0mEQIhSqRDTyyDlx95JY0V3GogBbZbQ=
|
||||||
github.com/beego/beego v1.12.11/go.mod h1:QURFL1HldOcCZAxnc1cZ7wrplsYR5dKPHFjmk6WkLAs=
|
github.com/beego/beego v1.12.12/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=
|
||||||
@@ -106,8 +107,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/casbin/casbin v1.7.0 h1:PuzlE8w0JBg/DhIqnkF1Dewf3z+qmUZMVN07PonvVUQ=
|
|
||||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||||
|
github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
|
||||||
|
github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
|
||||||
github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
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=
|
||||||
@@ -161,12 +163,16 @@ github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D
|
|||||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
|
github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
|
github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI=
|
||||||
|
github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
|
||||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
@@ -202,10 +208,12 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
|
|||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
|
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyDe9tvqI=
|
github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyDe9tvqI=
|
||||||
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
|
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
@@ -270,8 +278,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
|||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
@@ -289,6 +299,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
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/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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
||||||
@@ -318,8 +330,9 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
||||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
@@ -353,9 +366,9 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
|
|||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
|
||||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
@@ -365,6 +378,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
@@ -374,6 +388,7 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
|||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
@@ -405,8 +420,9 @@ github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmt
|
|||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.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/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||||
|
github.com/lib/pq v1.10.2/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 h1:wIONC+HMNRqmWBjuMxhatuSzHaljStc4gjDeKycxy0A=
|
||||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
|
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
@@ -416,8 +432,8 @@ github.com/markbates/goth v1.75.2 h1:C7KloBMMk50JyXaHhzfqWYLW6+bDcSVIvUGHXneLWro
|
|||||||
github.com/markbates/goth v1.75.2/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
|
github.com/markbates/goth v1.75.2/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc=
|
||||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911 h1:erppMjjp69Rertg1zlgRbLJH1u+eCmRPxKjMZ5I8/Ro=
|
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||||
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||||
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
||||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
@@ -442,6 +458,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=
|
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=
|
||||||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
|
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
||||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||||
@@ -476,13 +493,17 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkoukk/tiktoken-go v0.1.1 h1:jtkYlIECjyM9OW1w4rjPmTohK4arORP9V25y6TM6nXo=
|
||||||
|
github.com/pkoukk/tiktoken-go v0.1.1/go.mod h1:boMWvk9pQCOTx11pgu0DrIdrAKgQzzJKUP6vLXaz7Rw=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
|
|
||||||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||||
|
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
@@ -491,13 +512,15 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
|
|||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
|
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||||
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
|
|
||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||||
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0 h1:q0y8TPa/sTwtriJPRe8gWL++PuZ+XbOUuvKU+hvtTYs=
|
github.com/qiangmzsx/string-adapter/v2 v2.1.0 h1:q0y8TPa/sTwtriJPRe8gWL++PuZ+XbOUuvKU+hvtTYs=
|
||||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0/go.mod h1:PElPB7b7HnGKTsuADAffFpOQXHqjEGJz1+U1a6yR5wA=
|
github.com/qiangmzsx/string-adapter/v2 v2.1.0/go.mod h1:PElPB7b7HnGKTsuADAffFpOQXHqjEGJz1+U1a6yR5wA=
|
||||||
@@ -513,19 +536,21 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/russellhaering/gosaml2 v0.6.0 h1:OED8FLgczXxXAPlKhnJHQfmEig52tDX2qeXdPtZRIKc=
|
github.com/russellhaering/gosaml2 v0.9.0 h1:CNMnH42z/GirrKjdmNrSS6bAAs47F9bPdl4PfRmVOIk=
|
||||||
github.com/russellhaering/gosaml2 v0.6.0/go.mod h1:CtzxpPr4+bevsATaqR0rw3aqrNlX274b+3C6vFTLCk8=
|
github.com/russellhaering/gosaml2 v0.9.0/go.mod h1:byViER/1YPUa0Puj9ROZblpoq2jsE7h/CJmitzX0geU=
|
||||||
github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o=
|
github.com/russellhaering/goxmldsig v1.2.0 h1:Y6GTTc9Un5hCxSzVz4UIWQ/zuVwDvzJk80guqzwx6Vg=
|
||||||
github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM=
|
github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
|
||||||
github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
|
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sashabaranov/go-openai v1.9.1 h1:3N52HkJKo9Zlo/oe1AVv5ZkCOny0ra58/ACvAxkN3MM=
|
||||||
|
github.com/sashabaranov/go-openai v1.9.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
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/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
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/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
|
||||||
|
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/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 h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||||
@@ -541,6 +566,7 @@ github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKz
|
|||||||
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=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
||||||
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
||||||
@@ -571,8 +597,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
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 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=
|
||||||
@@ -692,8 +719,9 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
@@ -750,8 +778,9 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS
|
|||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -809,6 +838,7 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -819,6 +849,7 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/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=
|
||||||
@@ -997,8 +1028,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
@@ -1031,8 +1064,9 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
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/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.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@@ -32,6 +32,7 @@ func TestGenerateI18nFrontend(t *testing.T) {
|
|||||||
applyToOtherLanguage("frontend", "ko", data)
|
applyToOtherLanguage("frontend", "ko", data)
|
||||||
applyToOtherLanguage("frontend", "ru", data)
|
applyToOtherLanguage("frontend", "ru", data)
|
||||||
applyToOtherLanguage("frontend", "vi", data)
|
applyToOtherLanguage("frontend", "vi", data)
|
||||||
|
applyToOtherLanguage("frontend", "pt", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateI18nBackend(t *testing.T) {
|
func TestGenerateI18nBackend(t *testing.T) {
|
||||||
@@ -47,4 +48,5 @@ func TestGenerateI18nBackend(t *testing.T) {
|
|||||||
applyToOtherLanguage("backend", "ko", data)
|
applyToOtherLanguage("backend", "ko", data)
|
||||||
applyToOtherLanguage("backend", "ru", data)
|
applyToOtherLanguage("backend", "ru", data)
|
||||||
applyToOtherLanguage("backend", "vi", data)
|
applyToOtherLanguage("backend", "vi", data)
|
||||||
|
applyToOtherLanguage("backend", "pt", data)
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
|
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
|
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
|
||||||
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein",
|
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.",
|
"Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.",
|
||||||
"Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.",
|
"Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.",
|
||||||
"Unknown type": "Unbekannter Typ",
|
"Unknown type": "Unbekannter Typ",
|
||||||
"Wrong parameter": "Falscher Parameter",
|
|
||||||
"Wrong verification code!": "Falscher Bestätigungscode!",
|
"Wrong verification code!": "Falscher Bestätigungscode!",
|
||||||
"You should verify your code in %d min!": "Du solltest deinen Code in %d Minuten verifizieren!",
|
"You should verify your code in %d min!": "Du solltest deinen Code in %d Minuten verifizieren!",
|
||||||
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
|
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Service %s and %s do not match"
|
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
"Affiliation cannot be blank": "Affiliation cannot be blank",
|
||||||
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
"DisplayName cannot be blank": "DisplayName cannot be blank",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
|
||||||
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
|
||||||
"Unknown type": "Unknown type",
|
"Unknown type": "Unknown type",
|
||||||
"Wrong parameter": "Wrong parameter",
|
|
||||||
"Wrong verification code!": "Wrong verification code!",
|
"Wrong verification code!": "Wrong verification code!",
|
||||||
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
"You should verify your code in %d min!": "You should verify your code in %d min!",
|
||||||
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
|
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Afiliación no puede estar en blanco",
|
"Affiliation cannot be blank": "Afiliación no puede estar en blanco",
|
||||||
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",
|
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.",
|
"Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.",
|
||||||
"Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.",
|
"Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.",
|
||||||
"Unknown type": "Tipo desconocido",
|
"Unknown type": "Tipo desconocido",
|
||||||
"Wrong parameter": "Parámetro incorrecto",
|
|
||||||
"Wrong verification code!": "¡Código de verificación incorrecto!",
|
"Wrong verification code!": "¡Código de verificación incorrecto!",
|
||||||
"You should verify your code in %d min!": "¡Deberías verificar tu código en %d minutos!",
|
"You should verify your code in %d min!": "¡Deberías verificar tu código en %d minutos!",
|
||||||
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
|
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
|
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Affiliation ne peut pas être vide",
|
"Affiliation cannot be blank": "Affiliation ne peut pas être vide",
|
||||||
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",
|
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.",
|
"Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.",
|
||||||
"Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.",
|
"Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.",
|
||||||
"Unknown type": "Type inconnu",
|
"Unknown type": "Type inconnu",
|
||||||
"Wrong parameter": "Mauvais paramètre",
|
|
||||||
"Wrong verification code!": "Mauvais code de vérification !",
|
"Wrong verification code!": "Mauvais code de vérification !",
|
||||||
"You should verify your code in %d min!": "Vous devriez vérifier votre code en %d min !",
|
"You should verify your code in %d min!": "Vous devriez vérifier votre code en %d min !",
|
||||||
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
|
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
|
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
|
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
|
||||||
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",
|
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.",
|
"Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.",
|
||||||
"Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.",
|
"Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.",
|
||||||
"Unknown type": "Tipe tidak diketahui",
|
"Unknown type": "Tipe tidak diketahui",
|
||||||
"Wrong parameter": "Parameter yang salah",
|
|
||||||
"Wrong verification code!": "Kode verifikasi salah!",
|
"Wrong verification code!": "Kode verifikasi salah!",
|
||||||
"You should verify your code in %d min!": "Anda harus memverifikasi kode Anda dalam %d menit!",
|
"You should verify your code in %d min!": "Anda harus memverifikasi kode Anda dalam %d menit!",
|
||||||
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
|
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "サービス%sと%sは一致しません"
|
"Service %s and %s do not match": "サービス%sと%sは一致しません"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "所属は空白にできません",
|
"Affiliation cannot be blank": "所属は空白にできません",
|
||||||
"DisplayName cannot be blank": "表示名は空白にできません",
|
"DisplayName cannot be blank": "表示名は空白にできません",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
|
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
|
||||||
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",
|
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",
|
||||||
"Unknown type": "不明なタイプ",
|
"Unknown type": "不明なタイプ",
|
||||||
"Wrong parameter": "誤ったパラメータ",
|
|
||||||
"Wrong verification code!": "誤った検証コードです!",
|
"Wrong verification code!": "誤った検証コードです!",
|
||||||
"You should verify your code in %d min!": "あなたは%d分であなたのコードを確認する必要があります!",
|
"You should verify your code in %d min!": "あなたは%d分であなたのコードを確認する必要があります!",
|
||||||
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
|
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
|
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
|
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
|
||||||
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",
|
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
|
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
|
||||||
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",
|
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",
|
||||||
"Unknown type": "알 수 없는 유형",
|
"Unknown type": "알 수 없는 유형",
|
||||||
"Wrong parameter": "잘못된 매개 변수입니다",
|
|
||||||
"Wrong verification code!": "잘못된 인증 코드입니다!",
|
"Wrong verification code!": "잘못된 인증 코드입니다!",
|
||||||
"You should verify your code in %d min!": "당신은 %d분 안에 코드를 검증해야 합니다!",
|
"You should verify your code in %d min!": "당신은 %d분 안에 코드를 검증해야 합니다!",
|
||||||
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
|
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Сервисы %s и %s не совпадают"
|
"Service %s and %s do not match": "Сервисы %s и %s не совпадают"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Принадлежность не может быть пустым значением",
|
"Affiliation cannot be blank": "Принадлежность не может быть пустым значением",
|
||||||
"DisplayName cannot be blank": "Имя отображения не может быть пустым",
|
"DisplayName cannot be blank": "Имя отображения не может быть пустым",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.",
|
"Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.",
|
||||||
"Unable to get the phone modify rule.": "Невозможно получить правило изменения телефона.",
|
"Unable to get the phone modify rule.": "Невозможно получить правило изменения телефона.",
|
||||||
"Unknown type": "Неизвестный тип",
|
"Unknown type": "Неизвестный тип",
|
||||||
"Wrong parameter": "Неправильный параметр",
|
|
||||||
"Wrong verification code!": "Неправильный код подтверждения!",
|
"Wrong verification code!": "Неправильный код подтверждения!",
|
||||||
"You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!",
|
"You should verify your code in %d min!": "Вы должны проверить свой код через %d минут!",
|
||||||
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
|
"the user does not exist, please sign up first": "Пользователь не существует, пожалуйста, сначала зарегистрируйтесь"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp"
|
"Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "Tình trạng liên kết không thể để trống",
|
"Affiliation cannot be blank": "Tình trạng liên kết không thể để trống",
|
||||||
"DisplayName cannot be blank": "Tên hiển thị không thể để trống",
|
"DisplayName cannot be blank": "Tên hiển thị không thể để trống",
|
||||||
@@ -60,10 +68,10 @@
|
|||||||
"Missing parameter": "Thiếu tham số",
|
"Missing parameter": "Thiếu tham số",
|
||||||
"Please login first": "Vui lòng đăng nhập trước",
|
"Please login first": "Vui lòng đăng nhập trước",
|
||||||
"The user: %s doesn't exist": "Người dùng: %s không tồn tại",
|
"The user: %s doesn't exist": "Người dùng: %s không tồn tại",
|
||||||
"don't support captchaProvider: ": "Không hỗ trợ captchaProvider:"
|
"don't support captchaProvider: ": "không hỗ trợ captchaProvider: "
|
||||||
},
|
},
|
||||||
"ldap": {
|
"ldap": {
|
||||||
"Ldap server exist": "Máy chủ Ldap tồn tại"
|
"Ldap server exist": "Máy chủ LDAP tồn tại"
|
||||||
},
|
},
|
||||||
"link": {
|
"link": {
|
||||||
"Please link first": "Vui lòng kết nối trước tiên",
|
"Please link first": "Vui lòng kết nối trước tiên",
|
||||||
@@ -130,7 +138,6 @@
|
|||||||
"Unable to get the email modify rule.": "Không thể lấy quy tắc sửa đổi email.",
|
"Unable to get the email modify rule.": "Không thể lấy quy tắc sửa đổi email.",
|
||||||
"Unable to get the phone modify rule.": "Không thể thay đổi quy tắc trên điện thoại.",
|
"Unable to get the phone modify rule.": "Không thể thay đổi quy tắc trên điện thoại.",
|
||||||
"Unknown type": "Loại không xác định",
|
"Unknown type": "Loại không xác định",
|
||||||
"Wrong parameter": "Tham số không đúng",
|
|
||||||
"Wrong verification code!": "Mã xác thực sai!",
|
"Wrong verification code!": "Mã xác thực sai!",
|
||||||
"You should verify your code in %d min!": "Bạn nên kiểm tra mã của mình trong %d phút!",
|
"You should verify your code in %d min!": "Bạn nên kiểm tra mã của mình trong %d phút!",
|
||||||
"the user does not exist, please sign up first": "Người dùng không tồn tại, vui lòng đăng ký trước"
|
"the user does not exist, please sign up first": "Người dùng không tồn tại, vui lòng đăng ký trước"
|
||||||
|
@@ -23,6 +23,14 @@
|
|||||||
"cas": {
|
"cas": {
|
||||||
"Service %s and %s do not match": "服务%s与%s不匹配"
|
"Service %s and %s do not match": "服务%s与%s不匹配"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"The chat type must be \\\"AI\\\"": "The chat type must be \\\"AI\\\"",
|
||||||
|
"The chat: %s is not found": "The chat: %s is not found",
|
||||||
|
"The message is invalid": "The message is invalid",
|
||||||
|
"The message: %s is not found": "The message: %s is not found",
|
||||||
|
"The provider: %s is invalid": "The provider: %s is invalid",
|
||||||
|
"The provider: %s is not found": "The provider: %s is not found"
|
||||||
|
},
|
||||||
"check": {
|
"check": {
|
||||||
"Affiliation cannot be blank": "工作单位不可为空",
|
"Affiliation cannot be blank": "工作单位不可为空",
|
||||||
"DisplayName cannot be blank": "显示名称不可为空",
|
"DisplayName cannot be blank": "显示名称不可为空",
|
||||||
@@ -75,7 +83,7 @@
|
|||||||
},
|
},
|
||||||
"organization": {
|
"organization": {
|
||||||
"Only admin can modify the %s.": "仅允许管理员可以修改%s",
|
"Only admin can modify the %s.": "仅允许管理员可以修改%s",
|
||||||
"The %s is immutable.": "%s是不可变的",
|
"The %s is immutable.": "%s 是不可变的",
|
||||||
"Unknown modify rule %s.": "未知的修改规则: %s"
|
"Unknown modify rule %s.": "未知的修改规则: %s"
|
||||||
},
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
@@ -130,13 +138,12 @@
|
|||||||
"Unable to get the email modify rule.": "无法获取邮箱修改规则",
|
"Unable to get the email modify rule.": "无法获取邮箱修改规则",
|
||||||
"Unable to get the phone modify rule.": "无法获取手机号修改规则",
|
"Unable to get the phone modify rule.": "无法获取手机号修改规则",
|
||||||
"Unknown type": "未知类型",
|
"Unknown type": "未知类型",
|
||||||
"Wrong parameter": "参数错误",
|
|
||||||
"Wrong verification code!": "验证码错误!",
|
"Wrong verification code!": "验证码错误!",
|
||||||
"You should verify your code in %d min!": "请在 %d 分钟内输入正确验证码",
|
"You should verify your code in %d min!": "请在 %d 分钟内输入正确验证码",
|
||||||
"the user does not exist, please sign up first": "用户不存在,请先注册"
|
"the user does not exist, please sign up first": "用户不存在,请先注册"
|
||||||
},
|
},
|
||||||
"webauthn": {
|
"webauthn": {
|
||||||
"Found no credentials for this user": "该用户没有WebAuthn凭据",
|
"Found no credentials for this user": "该用户没有 WebAuthn 凭据",
|
||||||
"Please call WebAuthnSigninBegin first": "请先调用WebAuthnSigninBegin函数"
|
"Please call WebAuthnSigninBegin first": "请先调用WebAuthnSigninBegin函数"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
i18n/util.go
30
i18n/util.go
@@ -73,21 +73,29 @@ func applyData(data1 *I18nData, data2 *I18nData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Translate(lang string, error string) string {
|
func Translate(language string, errorText string) string {
|
||||||
parts := strings.SplitN(error, ":", 2)
|
tokens := strings.SplitN(errorText, ":", 2)
|
||||||
if !strings.Contains(error, ":") || len(parts) != 2 {
|
if !strings.Contains(errorText, ":") || len(tokens) != 2 {
|
||||||
return "Translate Error: " + error
|
return fmt.Sprintf("Translate error: the error text doesn't contain \":\", errorText = %s", errorText)
|
||||||
}
|
}
|
||||||
if langMap[lang] != nil {
|
|
||||||
return langMap[lang][parts[0]][parts[1]]
|
if langMap[language] == nil {
|
||||||
} else {
|
file, err := f.ReadFile(fmt.Sprintf("locales/%s/data.json", language))
|
||||||
file, _ := f.ReadFile("locales/" + lang + "/data.json")
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Translate error: the language \"%s\" is not supported, err = %s", language, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
data := I18nData{}
|
data := I18nData{}
|
||||||
err := util.JsonToStruct(string(file), &data)
|
err = util.JsonToStruct(string(file), &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
langMap[lang] = data
|
langMap[language] = data
|
||||||
return langMap[lang][parts[0]][parts[1]]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res := langMap[language][tokens[0]][tokens[1]]
|
||||||
|
if res == "" {
|
||||||
|
res = tokens[1]
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ package idp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -83,7 +84,7 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
|
|
||||||
// check if token is expired
|
// check if token is expired
|
||||||
if pToken.ExpiresIn <= 0 {
|
if pToken.ExpiresIn <= 0 {
|
||||||
return nil, fmt.Errorf("%s", pToken.AccessToken)
|
return nil, errors.New(pToken.AccessToken)
|
||||||
}
|
}
|
||||||
token := &oauth2.Token{
|
token := &oauth2.Token{
|
||||||
AccessToken: pToken.AccessToken,
|
AccessToken: pToken.AccessToken,
|
||||||
|
@@ -23,6 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -125,8 +126,8 @@ type DingTalkUserResponse struct {
|
|||||||
UnionId string `json:"unionId"`
|
UnionId string `json:"unionId"`
|
||||||
AvatarUrl string `json:"avatarUrl"`
|
AvatarUrl string `json:"avatarUrl"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Errmsg string `json:"message"`
|
Mobile string `json:"mobile"`
|
||||||
Errcode string `json:"code"`
|
StateCode string `json:"stateCode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserInfo Use access_token to get UserInfo
|
// GetUserInfo Use access_token to get UserInfo
|
||||||
@@ -156,8 +157,9 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dtUserInfo.Errmsg != "" {
|
countryCode, err := util.GetCountryCode(dtUserInfo.StateCode, dtUserInfo.Mobile)
|
||||||
return nil, fmt.Errorf("userIdResp.Errcode = %s, userIdResp.Errmsg = %s", dtUserInfo.Errcode, dtUserInfo.Errmsg)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo := UserInfo{
|
userInfo := UserInfo{
|
||||||
@@ -166,6 +168,8 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
|||||||
DisplayName: dtUserInfo.Nick,
|
DisplayName: dtUserInfo.Nick,
|
||||||
UnionId: dtUserInfo.UnionId,
|
UnionId: dtUserInfo.UnionId,
|
||||||
Email: dtUserInfo.Email,
|
Email: dtUserInfo.Email,
|
||||||
|
Phone: dtUserInfo.Mobile,
|
||||||
|
CountryCode: countryCode,
|
||||||
AvatarUrl: dtUserInfo.AvatarUrl,
|
AvatarUrl: dtUserInfo.AvatarUrl,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +179,19 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
corpEmail, err := idp.getUserCorpEmail(userId, corpAccessToken)
|
corpMobile, corpEmail, jobNumber, err := idp.getUserCorpEmail(userId, corpAccessToken)
|
||||||
if err == nil && corpEmail != "" {
|
if err == nil {
|
||||||
userInfo.Email = corpEmail
|
if corpMobile != "" {
|
||||||
|
userInfo.Phone = corpMobile
|
||||||
|
}
|
||||||
|
|
||||||
|
if corpEmail != "" {
|
||||||
|
userInfo.Email = corpEmail
|
||||||
|
}
|
||||||
|
|
||||||
|
if jobNumber != "" {
|
||||||
|
userInfo.Username = jobNumber
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &userInfo, nil
|
return &userInfo, nil
|
||||||
@@ -247,33 +261,36 @@ func (idp *DingTalkIdProvider) getUserId(unionId string, accessToken string) (st
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if data.ErrCode == 60121 {
|
if data.ErrCode == 60121 {
|
||||||
return "", fmt.Errorf("the user is not found in the organization where clientId and clientSecret belong")
|
return "", fmt.Errorf("该应用只允许本企业内部用户登录,您不属于该企业,无法登录")
|
||||||
} else if data.ErrCode != 0 {
|
} else if data.ErrCode != 0 {
|
||||||
return "", fmt.Errorf(data.ErrMessage)
|
return "", fmt.Errorf(data.ErrMessage)
|
||||||
}
|
}
|
||||||
return data.Result.UserId, nil
|
return data.Result.UserId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (string, error) {
|
func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (string, string, string, error) {
|
||||||
|
// https://open.dingtalk.com/document/isvapp/query-user-details
|
||||||
body := make(map[string]string)
|
body := make(map[string]string)
|
||||||
body["userid"] = userId
|
body["userid"] = userId
|
||||||
respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken)
|
respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
ErrMessage string `json:"errmsg"`
|
ErrMessage string `json:"errmsg"`
|
||||||
Result struct {
|
Result struct {
|
||||||
Email string `json:"email"`
|
Mobile string `json:"mobile"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
JobNumber string `json:"job_number"`
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(respBytes, &data)
|
err = json.Unmarshal(respBytes, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
if data.ErrMessage != "ok" {
|
if data.ErrMessage != "ok" {
|
||||||
return "", fmt.Errorf(data.ErrMessage)
|
return "", "", "", fmt.Errorf(data.ErrMessage)
|
||||||
}
|
}
|
||||||
return data.Result.Email, nil
|
return data.Result.Mobile, data.Result.Email, data.Result.JobNumber, nil
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,8 @@ type UserInfo struct {
|
|||||||
DisplayName string
|
DisplayName string
|
||||||
UnionId string
|
UnionId string
|
||||||
Email string
|
Email string
|
||||||
|
Phone string
|
||||||
|
CountryCode string
|
||||||
AvatarUrl string
|
AvatarUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,9 @@ func (idp *WeComIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
ProviderSecret string `json:"provider_secret"`
|
ProviderSecret string `json:"provider_secret"`
|
||||||
}{idp.Config.ClientID, idp.Config.ClientSecret}
|
}{idp.Config.ClientID, idp.Config.ClientSecret}
|
||||||
data, err := idp.postWithBody(pTokenParams, "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token")
|
data, err := idp.postWithBody(pTokenParams, "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
pToken := &WeComProviderToken{}
|
pToken := &WeComProviderToken{}
|
||||||
err = json.Unmarshal(data, pToken)
|
err = json.Unmarshal(data, pToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -53,7 +53,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindPassword := string(r.AuthenticationSimple())
|
bindPassword := string(r.AuthenticationSimple())
|
||||||
bindUser, err := object.CheckUserPassword(object.CasdoorOrganization, bindUsername, bindPassword, "en")
|
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
|
||||||
if err != "" {
|
if err != "" {
|
||||||
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
||||||
res.SetResultCode(ldap.LDAPResultInvalidCredentials)
|
res.SetResultCode(ldap.LDAPResultInvalidCredentials)
|
||||||
@@ -113,6 +113,9 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
|
|
||||||
for _, attr := range r.Attributes() {
|
for _, attr := range r.Attributes() {
|
||||||
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
|
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
|
||||||
|
if string(attr) == "cn" {
|
||||||
|
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(e)
|
w.Write(e)
|
||||||
|
51
ldap/util.go
51
ldap/util.go
@@ -57,16 +57,32 @@ func getNameAndOrgFromFilter(baseDN, filter string) (string, string, int) {
|
|||||||
func getUsername(filter string) string {
|
func getUsername(filter string) string {
|
||||||
nameIndex := strings.Index(filter, "cn=")
|
nameIndex := strings.Index(filter, "cn=")
|
||||||
if nameIndex == -1 {
|
if nameIndex == -1 {
|
||||||
return "*"
|
nameIndex = strings.Index(filter, "uid=")
|
||||||
|
if nameIndex == -1 {
|
||||||
|
return "*"
|
||||||
|
} else {
|
||||||
|
nameIndex += 4
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nameIndex += 3
|
||||||
}
|
}
|
||||||
|
|
||||||
var name string
|
var name string
|
||||||
for i := nameIndex + 3; filter[i] != ')'; i++ {
|
for i := nameIndex; filter[i] != ')'; i++ {
|
||||||
name = name + string(filter[i])
|
name = name + string(filter[i])
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringInSlice(value string, list []string) bool {
|
||||||
|
for _, item := range list {
|
||||||
|
if item == value {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) {
|
func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) {
|
||||||
r := m.GetSearchRequest()
|
r := m.GetSearchRequest()
|
||||||
|
|
||||||
@@ -87,13 +103,32 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
|
|||||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hasPermission, err := object.CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), true, "en")
|
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
|
||||||
|
userId := util.GetId(org, name)
|
||||||
|
|
||||||
|
hasPermission, err := object.CheckUserPermission(requestUserId, userId, true, "en")
|
||||||
if !hasPermission {
|
if !hasPermission {
|
||||||
log.Printf("ErrMsg = %v", err.Error())
|
log.Printf("ErrMsg = %v", err.Error())
|
||||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||||
}
|
}
|
||||||
user := object.GetUser(util.GetId(org, name))
|
|
||||||
filteredUsers = append(filteredUsers, user)
|
user := object.GetUser(userId)
|
||||||
|
if user != nil {
|
||||||
|
filteredUsers = append(filteredUsers, user)
|
||||||
|
return filteredUsers, ldap.LDAPResultSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
organization := object.GetOrganization(util.GetId("admin", org))
|
||||||
|
if organization == nil {
|
||||||
|
return nil, ldap.LDAPResultNoSuchObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if !stringInSlice(name, organization.Tags) {
|
||||||
|
return nil, ldap.LDAPResultNoSuchObject
|
||||||
|
}
|
||||||
|
|
||||||
|
users := object.GetUsersByTag(org, name)
|
||||||
|
filteredUsers = append(filteredUsers, users...)
|
||||||
return filteredUsers, ldap.LDAPResultSuccess
|
return filteredUsers, ldap.LDAPResultSuccess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,10 +158,16 @@ func getAttribute(attributeName string, user *object.User) message.AttributeValu
|
|||||||
return message.AttributeValue(user.Name)
|
return message.AttributeValue(user.Name)
|
||||||
case "uid":
|
case "uid":
|
||||||
return message.AttributeValue(user.Name)
|
return message.AttributeValue(user.Name)
|
||||||
|
case "displayname":
|
||||||
|
return message.AttributeValue(user.DisplayName)
|
||||||
case "email":
|
case "email":
|
||||||
return message.AttributeValue(user.Email)
|
return message.AttributeValue(user.Email)
|
||||||
|
case "mail":
|
||||||
|
return message.AttributeValue(user.Email)
|
||||||
case "mobile":
|
case "mobile":
|
||||||
return message.AttributeValue(user.Phone)
|
return message.AttributeValue(user.Phone)
|
||||||
|
case "title":
|
||||||
|
return message.AttributeValue(user.Tag)
|
||||||
case "userPassword":
|
case "userPassword":
|
||||||
return message.AttributeValue(getUserPasswordWithType(user))
|
return message.AttributeValue(getUserPasswordWithType(user))
|
||||||
default:
|
default:
|
||||||
|
3
main.go
3
main.go
@@ -27,7 +27,6 @@ import (
|
|||||||
"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"
|
||||||
_ "github.com/casdoor/casdoor/routers"
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,6 +58,7 @@ func main() {
|
|||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
|
||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
|
||||||
|
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
|
||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||||
|
|
||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
@@ -82,6 +82,7 @@ func main() {
|
|||||||
logs.SetLogFuncCall(false)
|
logs.SetLogFuncCall(false)
|
||||||
|
|
||||||
go ldap.StartLdapServer()
|
go ldap.StartLdapServer()
|
||||||
|
go object.ClearThroughputPerSecond()
|
||||||
|
|
||||||
beego.Run(fmt.Sprintf(":%v", port))
|
beego.Run(fmt.Sprintf(":%v", port))
|
||||||
}
|
}
|
||||||
|
@@ -240,6 +240,21 @@ func (a *Adapter) createTable() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Subscription))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Plan))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Engine.Sync2(new(Pricing))
|
||||||
|
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 {
|
||||||
|
@@ -38,7 +38,7 @@ type Application struct {
|
|||||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
|
|
||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
Logo string `xorm:"varchar(100)" json:"logo"`
|
Logo string `xorm:"varchar(200)" json:"logo"`
|
||||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||||
@@ -51,6 +51,7 @@ type Application struct {
|
|||||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||||
EnableWebAuthn bool `json:"enableWebAuthn"`
|
EnableWebAuthn bool `json:"enableWebAuthn"`
|
||||||
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
|
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
|
||||||
|
OrgChoiceMode string `json:"orgChoiceMode"`
|
||||||
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
|
||||||
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
|
||||||
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
|
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
|
||||||
@@ -72,6 +73,7 @@ type Application struct {
|
|||||||
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
|
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
|
||||||
ThemeData *ThemeData `xorm:"json" json:"themeData"`
|
ThemeData *ThemeData `xorm:"json" json:"themeData"`
|
||||||
FormCss string `xorm:"text" json:"formCss"`
|
FormCss string `xorm:"text" json:"formCss"`
|
||||||
|
FormCssMobile string `xorm:"text" json:"formCssMobile"`
|
||||||
FormOffset int `json:"formOffset"`
|
FormOffset int `json:"formOffset"`
|
||||||
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
|
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
|
||||||
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
|
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
|
||||||
@@ -109,7 +111,7 @@ func GetApplications(owner string) []*Application {
|
|||||||
|
|
||||||
func GetOrganizationApplications(owner string, organization string) []*Application {
|
func GetOrganizationApplications(owner string, organization string) []*Application {
|
||||||
applications := []*Application{}
|
applications := []*Application{}
|
||||||
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Owner: owner, Organization: organization})
|
err := adapter.Engine.Desc("created_time").Find(&applications, &Application{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -131,7 +133,7 @@ func GetPaginationApplications(owner string, offset, limit int, field, value, so
|
|||||||
func GetPaginationOrganizationApplications(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Application {
|
func GetPaginationOrganizationApplications(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Application {
|
||||||
applications := []*Application{}
|
applications := []*Application{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&applications, &Application{Owner: owner, Organization: organization})
|
err := session.Find(&applications, &Application{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -144,12 +146,12 @@ func getProviderMap(owner string) map[string]*Provider {
|
|||||||
m := map[string]*Provider{}
|
m := map[string]*Provider{}
|
||||||
for _, provider := range providers {
|
for _, provider := range providers {
|
||||||
// Get QRCode only once
|
// Get QRCode only once
|
||||||
if provider.Type == "WeChat" && provider.DisableSsl == true && provider.Content == "" {
|
if provider.Type == "WeChat" && provider.DisableSsl && provider.Content == "" {
|
||||||
provider.Content, _ = idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2)
|
provider.Content, _ = idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2)
|
||||||
UpdateProvider(provider.Owner+"/"+provider.Name, provider)
|
UpdateProvider(provider.Owner+"/"+provider.Name, provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
m[provider.Name] = GetMaskedProvider(provider)
|
m[provider.Name] = GetMaskedProvider(provider, true)
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
@@ -325,6 +327,12 @@ func UpdateApplication(id string, application *Application) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddApplication(application *Application) bool {
|
func AddApplication(application *Application) bool {
|
||||||
|
if application.Owner == "" {
|
||||||
|
application.Owner = "admin"
|
||||||
|
}
|
||||||
|
if application.Organization == "" {
|
||||||
|
application.Organization = "built-in"
|
||||||
|
}
|
||||||
if application.ClientId == "" {
|
if application.ClientId == "" {
|
||||||
application.ClientId = util.GenerateClientId()
|
application.ClientId = util.GenerateClientId()
|
||||||
}
|
}
|
||||||
|
@@ -46,9 +46,9 @@ type CasbinAdapter struct {
|
|||||||
Adapter *xormadapter.Adapter `xorm:"-" json:"-"`
|
Adapter *xormadapter.Adapter `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCasbinAdapterCount(owner, field, value string) int {
|
func GetCasbinAdapterCount(owner, organization, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&CasbinAdapter{})
|
count, err := session.Count(&CasbinAdapter{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -56,9 +56,9 @@ func GetCasbinAdapterCount(owner, field, value string) int {
|
|||||||
return int(count)
|
return int(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCasbinAdapters(owner string) []*CasbinAdapter {
|
func GetCasbinAdapters(owner string, organization string) []*CasbinAdapter {
|
||||||
adapters := []*CasbinAdapter{}
|
adapters := []*CasbinAdapter{}
|
||||||
err := adapter.Engine.Where("owner = ?", owner).Find(&adapters)
|
err := adapter.Engine.Where("owner = ? and organization = ?", owner, organization).Find(&adapters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -66,10 +66,10 @@ func GetCasbinAdapters(owner string) []*CasbinAdapter {
|
|||||||
return adapters
|
return adapters
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationCasbinAdapters(owner string, page, limit int, field, value, sort, order string) []*CasbinAdapter {
|
func GetPaginationCasbinAdapters(owner, organization string, page, limit int, field, value, sort, order string) []*CasbinAdapter {
|
||||||
session := GetSession(owner, page, limit, field, value, sort, order)
|
session := GetSession(owner, page, limit, field, value, sort, order)
|
||||||
adapters := []*CasbinAdapter{}
|
adapters := []*CasbinAdapter{}
|
||||||
err := session.Find(&adapters)
|
err := session.Find(&adapters, &CasbinAdapter{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -55,8 +55,8 @@ func GetMaskedCerts(certs []*Cert) []*Cert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetCertCount(owner, field, value string) int {
|
func GetCertCount(owner, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession("", -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Cert{})
|
count, err := session.Where("owner = ? or owner = ? ", "admin", owner).Count(&Cert{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func GetCertCount(owner, field, value string) int {
|
|||||||
|
|
||||||
func GetCerts(owner string) []*Cert {
|
func GetCerts(owner string) []*Cert {
|
||||||
certs := []*Cert{}
|
certs := []*Cert{}
|
||||||
err := adapter.Engine.Desc("created_time").Find(&certs, &Cert{Owner: owner})
|
err := adapter.Engine.Where("owner = ? or owner = ? ", "admin", owner).Desc("created_time").Find(&certs, &Cert{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,38 @@ func GetCerts(owner string) []*Cert {
|
|||||||
|
|
||||||
func GetPaginationCerts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Cert {
|
func GetPaginationCerts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Cert {
|
||||||
certs := []*Cert{}
|
certs := []*Cert{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Where("owner = ? or owner = ? ", "admin", owner).Find(&certs)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGlobalCertsCount(field, value string) int {
|
||||||
|
session := GetSession("", -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&Cert{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGlobleCerts() []*Cert {
|
||||||
|
certs := []*Cert{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&certs)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationGlobalCerts(offset, limit int, field, value, sortField, sortOrder string) []*Cert {
|
||||||
|
certs := []*Cert{}
|
||||||
|
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&certs)
|
err := session.Find(&certs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -103,6 +134,24 @@ func getCert(owner string, name string) *Cert {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCertByName(name string) *Cert {
|
||||||
|
if name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cert := Cert{Name: name}
|
||||||
|
existed, err := adapter.Engine.Get(&cert)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
return &cert
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetCert(id string) *Cert {
|
func GetCert(id string) *Cert {
|
||||||
owner, name := util.GetOwnerAndNameFromId(id)
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
return getCert(owner, name)
|
return getCert(owner, name)
|
||||||
@@ -158,7 +207,7 @@ func (p *Cert) GetId() string {
|
|||||||
|
|
||||||
func getCertByApplication(application *Application) *Cert {
|
func getCertByApplication(application *Application) *Cert {
|
||||||
if application.Cert != "" {
|
if application.Cert != "" {
|
||||||
return getCert("admin", application.Cert)
|
return getCertByName(application.Cert)
|
||||||
} else {
|
} else {
|
||||||
return GetDefaultCert()
|
return GetDefaultCert()
|
||||||
}
|
}
|
||||||
|
@@ -121,6 +121,13 @@ func UpdateChat(id string, chat *Chat) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddChat(chat *Chat) bool {
|
func AddChat(chat *Chat) bool {
|
||||||
|
if chat.Type == "AI" && chat.User2 == "" {
|
||||||
|
provider := getDefaultAiProvider()
|
||||||
|
if provider != nil {
|
||||||
|
chat.User2 = provider.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.Insert(chat)
|
affected, err := adapter.Engine.Insert(chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -135,6 +142,10 @@ func DeleteChat(chat *Chat) bool {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if affected != 0 {
|
||||||
|
return DeleteChatMessages(chat.Name)
|
||||||
|
}
|
||||||
|
|
||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/cred"
|
"github.com/casdoor/casdoor/cred"
|
||||||
|
"github.com/casdoor/casdoor/form"
|
||||||
"github.com/casdoor/casdoor/i18n"
|
"github.com/casdoor/casdoor/i18n"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
@@ -42,86 +43,86 @@ func init() {
|
|||||||
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, countryCode string, affiliation string, lang string) string {
|
func CheckUserSignup(application *Application, organization *Organization, form *form.AuthForm, lang string) string {
|
||||||
if organization == nil {
|
if organization == nil {
|
||||||
return i18n.Translate(lang, "check:Organization does not exist")
|
return i18n.Translate(lang, "check:Organization does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Username") {
|
if application.IsSignupItemVisible("Username") {
|
||||||
if len(username) <= 1 {
|
if len(form.Username) <= 1 {
|
||||||
return i18n.Translate(lang, "check:Username must have at least 2 characters")
|
return i18n.Translate(lang, "check:Username must have at least 2 characters")
|
||||||
}
|
}
|
||||||
if unicode.IsDigit(rune(username[0])) {
|
if unicode.IsDigit(rune(form.Username[0])) {
|
||||||
return i18n.Translate(lang, "check:Username cannot start with a digit")
|
return i18n.Translate(lang, "check:Username cannot start with a digit")
|
||||||
}
|
}
|
||||||
if util.IsEmailValid(username) {
|
if util.IsEmailValid(form.Username) {
|
||||||
return i18n.Translate(lang, "check:Username cannot be an email address")
|
return i18n.Translate(lang, "check:Username cannot be an email address")
|
||||||
}
|
}
|
||||||
if reWhiteSpace.MatchString(username) {
|
if reWhiteSpace.MatchString(form.Username) {
|
||||||
return i18n.Translate(lang, "check:Username cannot contain white spaces")
|
return i18n.Translate(lang, "check:Username cannot contain white spaces")
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg := CheckUsername(username, lang); msg != "" {
|
if msg := CheckUsername(form.Username, lang); msg != "" {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
if HasUserByField(organization.Name, "name", username) {
|
if HasUserByField(organization.Name, "name", form.Username) {
|
||||||
return i18n.Translate(lang, "check:Username already exists")
|
return i18n.Translate(lang, "check:Username already exists")
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "email", email) {
|
if HasUserByField(organization.Name, "email", form.Email) {
|
||||||
return i18n.Translate(lang, "check:Email already exists")
|
return i18n.Translate(lang, "check:Email already exists")
|
||||||
}
|
}
|
||||||
if HasUserByField(organization.Name, "phone", phone) {
|
if HasUserByField(organization.Name, "phone", form.Phone) {
|
||||||
return i18n.Translate(lang, "check:Phone already exists")
|
return i18n.Translate(lang, "check:Phone already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(password) <= 5 {
|
if len(form.Password) <= 5 {
|
||||||
return i18n.Translate(lang, "check:Password must have at least 6 characters")
|
return i18n.Translate(lang, "check:Password must have at least 6 characters")
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Email") {
|
if application.IsSignupItemVisible("Email") {
|
||||||
if email == "" {
|
if form.Email == "" {
|
||||||
if application.IsSignupItemRequired("Email") {
|
if application.IsSignupItemRequired("Email") {
|
||||||
return i18n.Translate(lang, "check:Email cannot be empty")
|
return i18n.Translate(lang, "check:Email cannot be empty")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if HasUserByField(organization.Name, "email", email) {
|
if HasUserByField(organization.Name, "email", form.Email) {
|
||||||
return i18n.Translate(lang, "check:Email already exists")
|
return i18n.Translate(lang, "check:Email already exists")
|
||||||
} else if !util.IsEmailValid(email) {
|
} else if !util.IsEmailValid(form.Email) {
|
||||||
return i18n.Translate(lang, "check:Email is invalid")
|
return i18n.Translate(lang, "check:Email is invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Phone") {
|
if application.IsSignupItemVisible("Phone") {
|
||||||
if phone == "" {
|
if form.Phone == "" {
|
||||||
if application.IsSignupItemRequired("Phone") {
|
if application.IsSignupItemRequired("Phone") {
|
||||||
return i18n.Translate(lang, "check:Phone cannot be empty")
|
return i18n.Translate(lang, "check:Phone cannot be empty")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if HasUserByField(organization.Name, "phone", phone) {
|
if HasUserByField(organization.Name, "phone", form.Phone) {
|
||||||
return i18n.Translate(lang, "check:Phone already exists")
|
return i18n.Translate(lang, "check:Phone already exists")
|
||||||
} else if !util.IsPhoneAllowInRegin(countryCode, organization.CountryCodes) {
|
} else if !util.IsPhoneAllowInRegin(form.CountryCode, organization.CountryCodes) {
|
||||||
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
|
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
|
||||||
} else if !util.IsPhoneValid(phone, countryCode) {
|
} else if !util.IsPhoneValid(form.Phone, form.CountryCode) {
|
||||||
return i18n.Translate(lang, "check:Phone number is invalid")
|
return i18n.Translate(lang, "check:Phone number is invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Display name") {
|
if application.IsSignupItemVisible("Display name") {
|
||||||
if application.GetSignupItemRule("Display name") == "First, last" && (firstName != "" || lastName != "") {
|
if application.GetSignupItemRule("Display name") == "First, last" && (form.FirstName != "" || form.LastName != "") {
|
||||||
if firstName == "" {
|
if form.FirstName == "" {
|
||||||
return i18n.Translate(lang, "check:FirstName cannot be blank")
|
return i18n.Translate(lang, "check:FirstName cannot be blank")
|
||||||
} else if lastName == "" {
|
} else if form.LastName == "" {
|
||||||
return i18n.Translate(lang, "check:LastName cannot be blank")
|
return i18n.Translate(lang, "check:LastName cannot be blank")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if displayName == "" {
|
if form.Name == "" {
|
||||||
return i18n.Translate(lang, "check:DisplayName cannot be blank")
|
return i18n.Translate(lang, "check:DisplayName cannot be blank")
|
||||||
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
} else if application.GetSignupItemRule("Display name") == "Real name" {
|
||||||
if !isValidRealName(displayName) {
|
if !isValidRealName(form.Name) {
|
||||||
return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
return i18n.Translate(lang, "check:DisplayName is not valid real name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +130,7 @@ func CheckUserSignup(application *Application, organization *Organization, usern
|
|||||||
}
|
}
|
||||||
|
|
||||||
if application.IsSignupItemVisible("Affiliation") {
|
if application.IsSignupItemVisible("Affiliation") {
|
||||||
if affiliation == "" {
|
if form.Affiliation == "" {
|
||||||
return i18n.Translate(lang, "check:Affiliation cannot be blank")
|
return i18n.Translate(lang, "check:Affiliation cannot be blank")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +175,11 @@ func CheckPassword(user *User, password string, lang string, options ...bool) st
|
|||||||
return i18n.Translate(lang, "check:Organization does not exist")
|
return i18n.Translate(lang, "check:Organization does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
credManager := cred.GetCredManager(organization.PasswordType)
|
passwordType := user.PasswordType
|
||||||
|
if passwordType == "" {
|
||||||
|
passwordType = organization.PasswordType
|
||||||
|
}
|
||||||
|
credManager := cred.GetCredManager(passwordType)
|
||||||
if credManager != nil {
|
if credManager != nil {
|
||||||
if organization.MasterPassword != "" {
|
if organization.MasterPassword != "" {
|
||||||
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
|
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
|
||||||
@@ -206,7 +211,7 @@ func checkLdapUserPassword(user *User, password string, lang string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
searchReq := goldap.NewSearchRequest(ldapServer.BaseDn, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases,
|
searchReq := goldap.NewSearchRequest(ldapServer.BaseDn, goldap.ScopeWholeSubtree, goldap.NeverDerefAliases,
|
||||||
0, 0, false, ldapServer.buildFilterString(user), []string{}, nil)
|
0, 0, false, ldapServer.buildAuthFilterString(user), []string{}, nil)
|
||||||
|
|
||||||
searchResult, err := conn.Conn.Search(searchReq)
|
searchResult, err := conn.Conn.Search(searchReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -243,7 +248,7 @@ func CheckUserPassword(organization string, username string, password string, la
|
|||||||
enableCaptcha = options[0]
|
enableCaptcha = options[0]
|
||||||
}
|
}
|
||||||
user := GetUserByFields(organization, username)
|
user := GetUserByFields(organization, username)
|
||||||
if user == nil || user.IsDeleted == true {
|
if user == nil || user.IsDeleted {
|
||||||
return nil, fmt.Sprintf(i18n.Translate(lang, "general:The user: %s doesn't exist"), util.GetId(organization, username))
|
return nil, fmt.Sprintf(i18n.Translate(lang, "general:The user: %s doesn't exist"), util.GetId(organization, username))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +286,10 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
|||||||
if userId != "" {
|
if userId != "" {
|
||||||
targetUser := GetUser(userId)
|
targetUser := GetUser(userId)
|
||||||
if targetUser == nil {
|
if targetUser == nil {
|
||||||
|
if strings.HasPrefix(requestUserId, "built-in/") {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
return false, fmt.Errorf(i18n.Translate(lang, "general:The user: %s doesn't exist"), userId)
|
return false, fmt.Errorf(i18n.Translate(lang, "general:The user: %s doesn't exist"), userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,6 +321,10 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CheckAccessPermission(userId string, application *Application) (bool, error) {
|
func CheckAccessPermission(userId string, application *Application) (bool, error) {
|
||||||
|
if userId == "built-in/admin" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
permissions := GetPermissions(application.Organization)
|
permissions := GetPermissions(application.Organization)
|
||||||
allowed := true
|
allowed := true
|
||||||
var err error
|
var err error
|
||||||
|
@@ -24,11 +24,9 @@ import (
|
|||||||
|
|
||||||
func getDialer(provider *Provider) *gomail.Dialer {
|
func getDialer(provider *Provider) *gomail.Dialer {
|
||||||
dialer := &gomail.Dialer{}
|
dialer := &gomail.Dialer{}
|
||||||
|
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
|
||||||
if provider.Type == "SUBMAIL" {
|
if provider.Type == "SUBMAIL" {
|
||||||
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.AppId, provider.ClientSecret)
|
|
||||||
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
} else {
|
|
||||||
dialer = gomail.NewDialer(provider.Host, provider.Port, provider.ClientId, provider.ClientSecret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dialer.SSL = !provider.DisableSsl
|
dialer.SSL = !provider.DisableSsl
|
||||||
@@ -40,14 +38,23 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
|
|||||||
dialer := getDialer(provider)
|
dialer := getDialer(provider)
|
||||||
|
|
||||||
message := gomail.NewMessage()
|
message := gomail.NewMessage()
|
||||||
message.SetAddressHeader("From", provider.ClientId, sender)
|
|
||||||
|
fromAddress := provider.ClientId2
|
||||||
|
if fromAddress == "" {
|
||||||
|
fromAddress = provider.ClientId
|
||||||
|
}
|
||||||
|
|
||||||
|
fromName := provider.ClientSecret2
|
||||||
|
if fromName == "" {
|
||||||
|
fromName = sender
|
||||||
|
}
|
||||||
|
|
||||||
|
message.SetAddressHeader("From", fromAddress, fromName)
|
||||||
message.SetHeader("To", dest)
|
message.SetHeader("To", dest)
|
||||||
message.SetHeader("Subject", title)
|
message.SetHeader("Subject", title)
|
||||||
message.SetBody("text/html", content)
|
message.SetBody("text/html", content)
|
||||||
|
|
||||||
if provider.Type == "Mailtrap" {
|
message.SkipUsernameCheck = true
|
||||||
message.SkipUsernameCheck = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialer.DialAndSend(message)
|
return dialer.DialAndSend(message)
|
||||||
}
|
}
|
||||||
|
@@ -67,6 +67,7 @@ func getBuiltInAccountItems() []*AccountItem {
|
|||||||
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||||
{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: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
{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"},
|
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||||
}
|
}
|
||||||
@@ -89,7 +90,7 @@ func initBuiltInOrganization() bool {
|
|||||||
CountryCodes: []string{"US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN"},
|
CountryCodes: []string{"US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN"},
|
||||||
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
|
||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
Languages: []string{"en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi"},
|
Languages: []string{"en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "pt"},
|
||||||
InitScore: 2000,
|
InitScore: 2000,
|
||||||
AccountItems: getBuiltInAccountItems(),
|
AccountItems: getBuiltInAccountItems(),
|
||||||
EnableSoftDeletion: false,
|
EnableSoftDeletion: false,
|
||||||
|
@@ -87,11 +87,13 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
|
|||||||
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
|
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
existed, failed := SyncLdapUsers(ldap.Owner, LdapUsersToLdapRespUsers(users), ldap.Id)
|
|
||||||
if len(*failed) != 0 {
|
existed, failed, err := SyncLdapUsers(ldap.Owner, AutoAdjustLdapUser(users), ldap.Id)
|
||||||
logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(*existed)-len(*failed), len(*failed)), *failed)
|
if len(failed) != 0 {
|
||||||
|
logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(existed)-len(failed), len(failed)), failed)
|
||||||
|
logs.Warning(err.Error())
|
||||||
} else {
|
} else {
|
||||||
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(*existed), len(*existed)))
|
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(existed), len(existed)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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"
|
||||||
@@ -35,35 +34,26 @@ type LdapConn struct {
|
|||||||
// Cn string
|
// Cn string
|
||||||
//}
|
//}
|
||||||
|
|
||||||
type ldapUser struct {
|
type LdapUser struct {
|
||||||
UidNumber string
|
UidNumber string `json:"uidNumber"`
|
||||||
Uid string
|
Uid string `json:"uid"`
|
||||||
Cn string
|
Cn string `json:"cn"`
|
||||||
GidNumber string
|
GidNumber string `json:"gidNumber"`
|
||||||
// Gcn string
|
// Gcn string
|
||||||
Uuid string
|
Uuid string `json:"uuid"`
|
||||||
DisplayName string
|
DisplayName string `json:"displayName"`
|
||||||
Mail string
|
Mail string
|
||||||
Email string
|
Email string `json:"email"`
|
||||||
EmailAddress string
|
EmailAddress string
|
||||||
TelephoneNumber string
|
TelephoneNumber string
|
||||||
Mobile string
|
Mobile string
|
||||||
MobileTelephoneNumber string
|
MobileTelephoneNumber string
|
||||||
RegisteredAddress string
|
RegisteredAddress string
|
||||||
PostalAddress string
|
PostalAddress string
|
||||||
}
|
|
||||||
|
|
||||||
type LdapRespUser struct {
|
GroupId string `json:"groupId"`
|
||||||
UidNumber string `json:"uidNumber"`
|
Phone string `json:"phone"`
|
||||||
Uid string `json:"uid"`
|
Address string `json:"address"`
|
||||||
Cn string `json:"cn"`
|
|
||||||
GroupId string `json:"groupId"`
|
|
||||||
// GroupName string `json:"groupName"`
|
|
||||||
Uuid string `json:"uuid"`
|
|
||||||
DisplayName string `json:"displayName"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Phone string `json:"phone"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
|
||||||
@@ -136,7 +126,7 @@ func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
|
|||||||
return isMicrosoft, err
|
return isMicrosoft, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
|
func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
|
||||||
SearchAttributes := []string{
|
SearchAttributes := []string{
|
||||||
"uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email",
|
"uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email",
|
||||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
|
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
|
||||||
@@ -159,9 +149,9 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
|
|||||||
return nil, errors.New("no result")
|
return nil, errors.New("no result")
|
||||||
}
|
}
|
||||||
|
|
||||||
var ldapUsers []ldapUser
|
var ldapUsers []LdapUser
|
||||||
for _, entry := range searchResult.Entries {
|
for _, entry := range searchResult.Entries {
|
||||||
var user ldapUser
|
var user LdapUser
|
||||||
for _, attribute := range entry.Attributes {
|
for _, attribute := range entry.Attributes {
|
||||||
switch attribute.Name {
|
switch attribute.Name {
|
||||||
case "uidNumber":
|
case "uidNumber":
|
||||||
@@ -241,35 +231,30 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
|
|||||||
// return groupMap, nil
|
// return groupMap, nil
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser {
|
func AutoAdjustLdapUser(users []LdapUser) []LdapUser {
|
||||||
res := make([]LdapRespUser, 0)
|
res := make([]LdapUser, len(users))
|
||||||
for _, user := range users {
|
for i, user := range users {
|
||||||
res = append(res, LdapRespUser{
|
res[i] = LdapUser{
|
||||||
UidNumber: user.UidNumber,
|
UidNumber: user.UidNumber,
|
||||||
Uid: user.Uid,
|
Uid: user.Uid,
|
||||||
Cn: user.Cn,
|
Cn: user.Cn,
|
||||||
GroupId: user.GidNumber,
|
GroupId: user.GidNumber,
|
||||||
Uuid: user.Uuid,
|
Uuid: user.GetLdapUuid(),
|
||||||
DisplayName: user.DisplayName,
|
DisplayName: user.DisplayName,
|
||||||
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
|
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
|
||||||
Phone: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
|
Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
|
||||||
Address: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
|
RegisteredAddress: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]LdapRespUser, *[]LdapRespUser) {
|
func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUsers []LdapUser, failedUsers []LdapUser, err error) {
|
||||||
var existUsers []LdapRespUser
|
|
||||||
var failedUsers []LdapRespUser
|
|
||||||
var uuids []string
|
var uuids []string
|
||||||
|
for _, user := range syncUsers {
|
||||||
for _, user := range respUsers {
|
|
||||||
uuids = append(uuids, user.Uuid)
|
uuids = append(uuids, user.Uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
existUuids := GetExistUuids(owner, uuids)
|
|
||||||
|
|
||||||
organization := getOrganization("admin", owner)
|
organization := getOrganization("admin", owner)
|
||||||
ldap := GetLdap(ldapId)
|
ldap := GetLdap(ldapId)
|
||||||
|
|
||||||
@@ -289,67 +274,59 @@ func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]Ld
|
|||||||
}
|
}
|
||||||
tag := strings.Join(ou, ".")
|
tag := strings.Join(ou, ".")
|
||||||
|
|
||||||
for _, respUser := range respUsers {
|
for _, syncUser := range syncUsers {
|
||||||
|
existUuids := GetExistUuids(owner, uuids)
|
||||||
found := false
|
found := false
|
||||||
if len(existUuids) > 0 {
|
if len(existUuids) > 0 {
|
||||||
for _, existUuid := range existUuids {
|
for _, existUuid := range existUuids {
|
||||||
if respUser.Uuid == existUuid {
|
if syncUser.Uuid == existUuid {
|
||||||
existUsers = append(existUsers, respUser)
|
existUsers = append(existUsers, syncUser)
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
|
score, _ := organization.GetInitScore()
|
||||||
newUser := &User{
|
newUser := &User{
|
||||||
Owner: owner,
|
Owner: owner,
|
||||||
Name: respUser.buildLdapUserName(),
|
Name: syncUser.buildLdapUserName(),
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: respUser.buildLdapDisplayName(),
|
DisplayName: syncUser.buildLdapDisplayName(),
|
||||||
Avatar: organization.DefaultAvatar,
|
Avatar: organization.DefaultAvatar,
|
||||||
Email: respUser.Email,
|
Email: syncUser.Email,
|
||||||
Phone: respUser.Phone,
|
Phone: syncUser.Phone,
|
||||||
Address: []string{respUser.Address},
|
Address: []string{syncUser.Address},
|
||||||
Affiliation: affiliation,
|
Affiliation: affiliation,
|
||||||
Tag: tag,
|
Tag: tag,
|
||||||
Score: beego.AppConfig.DefaultInt("initScore", 2000),
|
Score: score,
|
||||||
Ldap: respUser.Uuid,
|
Ldap: syncUser.Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
affected := AddUser(newUser)
|
affected := AddUser(newUser)
|
||||||
if !affected {
|
if !affected {
|
||||||
failedUsers = append(failedUsers, respUser)
|
failedUsers = append(failedUsers, syncUser)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &existUsers, &failedUsers
|
return existUsers, failedUsers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetExistUuids(owner string, uuids []string) []string {
|
func GetExistUuids(owner string, uuids []string) []string {
|
||||||
var users []User
|
|
||||||
var existUuids []string
|
var existUuids []string
|
||||||
existUuidSet := make(map[string]struct{})
|
|
||||||
|
|
||||||
err := adapter.Engine.Where(fmt.Sprintf("ldap IN (%s) AND owner = ?", "'"+strings.Join(uuids, "','")+"'"), owner).Find(&users)
|
err := adapter.Engine.Table("user").Where("owner = ?", owner).Cols("ldap").
|
||||||
|
In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(users) > 0 {
|
|
||||||
for _, result := range users {
|
|
||||||
existUuidSet[result.Ldap] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for uuid := range existUuidSet {
|
|
||||||
existUuids = append(existUuids, uuid)
|
|
||||||
}
|
|
||||||
return existUuids
|
return existUuids
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldapUser *LdapRespUser) buildLdapUserName() string {
|
func (ldapUser *LdapUser) buildLdapUserName() string {
|
||||||
user := User{}
|
user := User{}
|
||||||
uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber)
|
uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber)
|
||||||
has, err := adapter.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user)
|
has, err := adapter.Engine.Where("name = ? or name = ?", ldapUser.Uid, uidWithNumber).Get(&user)
|
||||||
@@ -364,10 +341,14 @@ func (ldapUser *LdapRespUser) buildLdapUserName() string {
|
|||||||
return fmt.Sprintf("%s_%s", uidWithNumber, randstr.Hex(6))
|
return fmt.Sprintf("%s_%s", uidWithNumber, randstr.Hex(6))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ldapUser.Uid
|
if ldapUser.Uid != "" {
|
||||||
|
return ldapUser.Uid
|
||||||
|
}
|
||||||
|
|
||||||
|
return ldapUser.Cn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldapUser *LdapRespUser) buildLdapDisplayName() string {
|
func (ldapUser *LdapUser) buildLdapDisplayName() string {
|
||||||
if ldapUser.DisplayName != "" {
|
if ldapUser.DisplayName != "" {
|
||||||
return ldapUser.DisplayName
|
return ldapUser.DisplayName
|
||||||
}
|
}
|
||||||
@@ -375,7 +356,18 @@ func (ldapUser *LdapRespUser) buildLdapDisplayName() string {
|
|||||||
return ldapUser.Cn
|
return ldapUser.Cn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ldap *Ldap) buildFilterString(user *User) string {
|
func (ldapUser *LdapUser) GetLdapUuid() string {
|
||||||
|
if ldapUser.Uuid != "" {
|
||||||
|
return ldapUser.Uuid
|
||||||
|
}
|
||||||
|
if ldapUser.Uid != "" {
|
||||||
|
return ldapUser.Uid
|
||||||
|
}
|
||||||
|
|
||||||
|
return ldapUser.Cn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ldap *Ldap) buildAuthFilterString(user *User) string {
|
||||||
if len(ldap.FilterFields) == 0 {
|
if len(ldap.FilterFields) == 0 {
|
||||||
return fmt.Sprintf("(&%s(uid=%s))", ldap.Filter, user.Name)
|
return fmt.Sprintf("(&%s(uid=%s))", ldap.Filter, user.Name)
|
||||||
}
|
}
|
||||||
@@ -393,6 +385,8 @@ func (user *User) getFieldFromLdapAttribute(attribute string) string {
|
|||||||
switch attribute {
|
switch attribute {
|
||||||
case "uid":
|
case "uid":
|
||||||
return user.Name
|
return user.Name
|
||||||
|
case "sAMAccountName":
|
||||||
|
return user.Name
|
||||||
case "mail":
|
case "mail":
|
||||||
return user.Email
|
return user.Email
|
||||||
case "mobile":
|
case "mobile":
|
||||||
|
@@ -28,6 +28,7 @@ type Message struct {
|
|||||||
|
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||||
Chat string `xorm:"varchar(100) index" json:"chat"`
|
Chat string `xorm:"varchar(100) index" json:"chat"`
|
||||||
|
ReplyTo string `xorm:"varchar(100) index" json:"replyTo"`
|
||||||
Author string `xorm:"varchar(100)" json:"author"`
|
Author string `xorm:"varchar(100)" json:"author"`
|
||||||
Text string `xorm:"mediumtext" json:"text"`
|
Text string `xorm:"mediumtext" json:"text"`
|
||||||
}
|
}
|
||||||
@@ -47,9 +48,9 @@ func GetMaskedMessages(messages []*Message) []*Message {
|
|||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMessageCount(owner, field, value string) int {
|
func GetMessageCount(owner, organization, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Message{})
|
count, err := session.Count(&Message{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -77,10 +78,10 @@ func GetChatMessages(chat string) []*Message {
|
|||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationMessages(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Message {
|
func GetPaginationMessages(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Message {
|
||||||
messages := []*Message{}
|
messages := []*Message{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&messages)
|
err := session.Find(&messages, &Message{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -143,6 +144,15 @@ func DeleteMessage(message *Message) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteChatMessages(chat string) bool {
|
||||||
|
affected, err := adapter.Engine.Delete(&Message{Chat: chat})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Message) GetId() string {
|
func (p *Message) GetId() string {
|
||||||
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
||||||
}
|
}
|
||||||
|
108
object/mfa.go
Normal file
108
object/mfa.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
|
||||||
|
"github.com/beego/beego/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MfaSessionData struct {
|
||||||
|
UserId string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MfaProps struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
IsPreferred bool `json:"isPreferred"`
|
||||||
|
AuthType string `json:"type" form:"type"`
|
||||||
|
Secret string `json:"secret,omitempty"`
|
||||||
|
CountryCode string `json:"countryCode,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
RecoveryCodes []string `json:"recoveryCodes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MfaInterface interface {
|
||||||
|
SetupVerify(ctx *context.Context, passCode string) error
|
||||||
|
Verify(passCode string) error
|
||||||
|
Initiate(ctx *context.Context, name1 string, name2 string) (*MfaProps, error)
|
||||||
|
Enable(ctx *context.Context, user *User) error
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SmsType = "sms"
|
||||||
|
TotpType = "app"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MfaSessionUserId = "MfaSessionUserId"
|
||||||
|
NextMfa = "NextMfa"
|
||||||
|
RequiredMfa = "RequiredMfa"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMfaUtil(providerType string, config *MfaProps) MfaInterface {
|
||||||
|
switch providerType {
|
||||||
|
case SmsType:
|
||||||
|
return NewSmsTwoFactor(config)
|
||||||
|
case TotpType:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverTfs(user *User, recoveryCode string) error {
|
||||||
|
hit := false
|
||||||
|
|
||||||
|
twoFactor := user.GetPreferMfa(false)
|
||||||
|
if len(twoFactor.RecoveryCodes) == 0 {
|
||||||
|
return fmt.Errorf("do not have recovery codes")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, code := range twoFactor.RecoveryCodes {
|
||||||
|
if code == recoveryCode {
|
||||||
|
hit = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hit {
|
||||||
|
return fmt.Errorf("recovery code not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
affected := UpdateUser(user.GetId(), user, []string{"two_factor_auth"}, user.IsAdminUser())
|
||||||
|
if !affected {
|
||||||
|
return fmt.Errorf("")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMaskedProps(props *MfaProps) *MfaProps {
|
||||||
|
maskedProps := &MfaProps{
|
||||||
|
AuthType: props.AuthType,
|
||||||
|
Id: props.Id,
|
||||||
|
IsPreferred: props.IsPreferred,
|
||||||
|
}
|
||||||
|
|
||||||
|
if props.AuthType == SmsType {
|
||||||
|
if !util.IsEmailValid(props.Secret) {
|
||||||
|
maskedProps.Secret = util.GetMaskedPhone(props.Secret)
|
||||||
|
} else {
|
||||||
|
maskedProps.Secret = util.GetMaskedEmail(props.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maskedProps
|
||||||
|
}
|
120
object/mfa_sms.go
Normal file
120
object/mfa_sms.go
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright 2023 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 (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
|
||||||
|
"github.com/beego/beego/context"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MfaSmsCountryCodeSession = "mfa_country_code"
|
||||||
|
MfaSmsDestSession = "mfa_dest"
|
||||||
|
MfaSmsRecoveryCodesSession = "mfa_recovery_codes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SmsMfa struct {
|
||||||
|
Config *MfaProps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mfa *SmsMfa) SetupVerify(ctx *context.Context, passCode string) error {
|
||||||
|
dest := ctx.Input.CruSession.Get(MfaSmsDestSession).(string)
|
||||||
|
countryCode := ctx.Input.CruSession.Get(MfaSmsCountryCodeSession).(string)
|
||||||
|
if !util.IsEmailValid(dest) {
|
||||||
|
dest, _ = util.GetE164Number(dest, countryCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := CheckVerificationCode(dest, passCode, "en"); result.Code != VerificationSuccess {
|
||||||
|
return errors.New(result.Msg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mfa *SmsMfa) Verify(passCode string) error {
|
||||||
|
if !util.IsEmailValid(mfa.Config.Secret) {
|
||||||
|
mfa.Config.Secret, _ = util.GetE164Number(mfa.Config.Secret, mfa.Config.CountryCode)
|
||||||
|
}
|
||||||
|
if result := CheckVerificationCode(mfa.Config.Secret, passCode, "en"); result.Code != VerificationSuccess {
|
||||||
|
return errors.New(result.Msg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mfa *SmsMfa) Initiate(ctx *context.Context, name string, secret string) (*MfaProps, error) {
|
||||||
|
recoveryCode, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctx.Input.CruSession.Set(MfaSmsRecoveryCodesSession, []string{recoveryCode.String()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mfaProps := MfaProps{
|
||||||
|
AuthType: SmsType,
|
||||||
|
RecoveryCodes: []string{recoveryCode.String()},
|
||||||
|
}
|
||||||
|
return &mfaProps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mfa *SmsMfa) Enable(ctx *context.Context, user *User) error {
|
||||||
|
dest := ctx.Input.CruSession.Get(MfaSmsDestSession).(string)
|
||||||
|
recoveryCodes := ctx.Input.CruSession.Get(MfaSmsRecoveryCodesSession).([]string)
|
||||||
|
countryCode := ctx.Input.CruSession.Get(MfaSmsCountryCodeSession).(string)
|
||||||
|
|
||||||
|
if dest == "" || len(recoveryCodes) == 0 {
|
||||||
|
return fmt.Errorf("MFA dest or recovery codes is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.IsEmailValid(dest) {
|
||||||
|
mfa.Config.CountryCode = countryCode
|
||||||
|
}
|
||||||
|
|
||||||
|
mfa.Config.AuthType = SmsType
|
||||||
|
mfa.Config.Id = uuid.NewString()
|
||||||
|
mfa.Config.Secret = dest
|
||||||
|
mfa.Config.RecoveryCodes = recoveryCodes
|
||||||
|
|
||||||
|
for i, mfaProp := range user.MultiFactorAuths {
|
||||||
|
if mfaProp.Secret == mfa.Config.Secret {
|
||||||
|
user.MultiFactorAuths = append(user.MultiFactorAuths[:i], user.MultiFactorAuths[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.MultiFactorAuths = append(user.MultiFactorAuths, mfa.Config)
|
||||||
|
|
||||||
|
affected := UpdateUser(user.GetId(), user, []string{"multi_factor_auths"}, user.IsAdminUser())
|
||||||
|
if !affected {
|
||||||
|
return fmt.Errorf("failed to enable two factor authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSmsTwoFactor(config *MfaProps) *SmsMfa {
|
||||||
|
if config == nil {
|
||||||
|
config = &MfaProps{
|
||||||
|
AuthType: SmsType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &SmsMfa{
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,7 @@ func DoMigration() {
|
|||||||
&Migrator_1_101_0_PR_1083{},
|
&Migrator_1_101_0_PR_1083{},
|
||||||
&Migrator_1_235_0_PR_1530{},
|
&Migrator_1_235_0_PR_1530{},
|
||||||
&Migrator_1_240_0_PR_1539{},
|
&Migrator_1_240_0_PR_1539{},
|
||||||
|
&Migrator_1_314_0_PR_1841{},
|
||||||
// more migrators add here in chronological order...
|
// more migrators add here in chronological order...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,10 +25,7 @@ type Migrator_1_235_0_PR_1530 struct{}
|
|||||||
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
|
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
|
||||||
exist, _ := adapter.Engine.IsTableExist("casbin_rule")
|
exist, _ := adapter.Engine.IsTableExist("casbin_rule")
|
||||||
|
|
||||||
if exist {
|
return exist
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Migrator_1_235_0_PR_1530) DoMigration() *migrate.Migration {
|
func (*Migrator_1_235_0_PR_1530) DoMigration() *migrate.Migration {
|
||||||
|
75
object/migrator_1_314_0_PR_1841.go
Normal file
75
object/migrator_1_314_0_PR_1841.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2023 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 (
|
||||||
|
"github.com/xorm-io/xorm"
|
||||||
|
"github.com/xorm-io/xorm/migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Migrator_1_314_0_PR_1841 struct{}
|
||||||
|
|
||||||
|
func (*Migrator_1_314_0_PR_1841) IsMigrationNeeded() bool {
|
||||||
|
users := []*User{}
|
||||||
|
|
||||||
|
err := adapter.Engine.Table("user").Find(&users)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range users {
|
||||||
|
if u.PasswordType != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Migrator_1_314_0_PR_1841) DoMigration() *migrate.Migration {
|
||||||
|
migration := migrate.Migration{
|
||||||
|
ID: "20230515MigrateUser--Create a new field 'passwordType' for table `user`",
|
||||||
|
Migrate: func(engine *xorm.Engine) error {
|
||||||
|
tx := engine.NewSession()
|
||||||
|
|
||||||
|
defer tx.Close()
|
||||||
|
|
||||||
|
err := tx.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
organizations := []*Organization{}
|
||||||
|
err = tx.Table("organization").Find(&organizations)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, organization := range organizations {
|
||||||
|
user := &User{PasswordType: organization.PasswordType}
|
||||||
|
_, err = tx.Where("owner = ?", organization.Name).Cols("password_type").Update(user)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &migration
|
||||||
|
}
|
@@ -55,13 +55,8 @@ func isIpAddress(host string) bool {
|
|||||||
|
|
||||||
// Attempt to parse the host as an IP address (both IPv4 and IPv6)
|
// Attempt to parse the host as an IP address (both IPv4 and IPv6)
|
||||||
ip := net.ParseIP(hostWithoutPort)
|
ip := net.ParseIP(hostWithoutPort)
|
||||||
if ip != nil {
|
// if host is not nil is an IP address else is not an IP address
|
||||||
// The host is an IP address
|
return ip != nil
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// The host is not an IP address
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOriginFromHost(host string) (string, string) {
|
func getOriginFromHost(host string) (string, string) {
|
||||||
|
@@ -16,7 +16,9 @@ package object
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/cred"
|
"github.com/casdoor/casdoor/cred"
|
||||||
"github.com/casdoor/casdoor/i18n"
|
"github.com/casdoor/casdoor/i18n"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@@ -38,6 +40,11 @@ type ThemeData struct {
|
|||||||
IsEnabled bool `xorm:"bool" json:"isEnabled"`
|
IsEnabled bool `xorm:"bool" json:"isEnabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MfaItem struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Rule string `json:"rule"`
|
||||||
|
}
|
||||||
|
|
||||||
type Organization struct {
|
type Organization struct {
|
||||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
@@ -49,7 +56,7 @@ type Organization struct {
|
|||||||
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||||
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
|
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
|
||||||
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
|
DefaultAvatar string `xorm:"varchar(200)" json:"defaultAvatar"`
|
||||||
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
|
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
|
||||||
Tags []string `xorm:"mediumtext" json:"tags"`
|
Tags []string `xorm:"mediumtext" json:"tags"`
|
||||||
Languages []string `xorm:"varchar(255)" json:"languages"`
|
Languages []string `xorm:"varchar(255)" json:"languages"`
|
||||||
@@ -59,6 +66,7 @@ type Organization struct {
|
|||||||
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
EnableSoftDeletion bool `json:"enableSoftDeletion"`
|
||||||
IsProfilePublic bool `json:"isProfilePublic"`
|
IsProfilePublic bool `json:"isProfilePublic"`
|
||||||
|
|
||||||
|
MfaItems []*MfaItem `xorm:"varchar(300)" json:"mfaItems"`
|
||||||
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
|
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +90,16 @@ func GetOrganizations(owner string) []*Organization {
|
|||||||
return organizations
|
return organizations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetOrganizationsByFields(owner string, fields ...string) []*Organization {
|
||||||
|
organizations := []*Organization{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Cols(fields...).Find(&organizations, &Organization{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return organizations
|
||||||
|
}
|
||||||
|
|
||||||
func GetPaginationOrganizations(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Organization {
|
func GetPaginationOrganizations(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Organization {
|
||||||
organizations := []*Organization{}
|
organizations := []*Organization{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
@@ -209,14 +227,14 @@ func GetAccountItemByName(name string, organization *Organization) *AccountItem
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckAccountItemModifyRule(accountItem *AccountItem, user *User, lang string) (bool, string) {
|
func CheckAccountItemModifyRule(accountItem *AccountItem, isAdmin bool, lang string) (bool, string) {
|
||||||
if accountItem == nil {
|
if accountItem == nil {
|
||||||
return true, ""
|
return true, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch accountItem.ModifyRule {
|
switch accountItem.ModifyRule {
|
||||||
case "Admin":
|
case "Admin":
|
||||||
if user == nil || !user.IsAdmin && !user.IsGlobalAdmin {
|
if !isAdmin {
|
||||||
return false, fmt.Sprintf(i18n.Translate(lang, "organization:Only admin can modify the %s."), accountItem.Name)
|
return false, fmt.Sprintf(i18n.Translate(lang, "organization:Only admin can modify the %s."), accountItem.Name)
|
||||||
}
|
}
|
||||||
case "Immutable":
|
case "Immutable":
|
||||||
@@ -408,3 +426,20 @@ func organizationChangeTrigger(oldName string, newName string) error {
|
|||||||
|
|
||||||
return session.Commit()
|
return session.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (org *Organization) HasRequiredMfa() bool {
|
||||||
|
for _, item := range org.MfaItems {
|
||||||
|
if item.Rule == "Required" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (org *Organization) GetInitScore() (int, error) {
|
||||||
|
if org != nil {
|
||||||
|
return org.InitScore, nil
|
||||||
|
} else {
|
||||||
|
return strconv.Atoi(conf.GetConfigString("initScore"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -152,46 +152,47 @@ func DeletePayment(payment *Payment) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string) (*Payment, error) {
|
func notifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string) (*Payment, error, string) {
|
||||||
|
provider := getProvider(owner, providerName)
|
||||||
|
|
||||||
|
pProvider, cert, err := provider.getPaymentProvider()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
payment := getPayment(owner, paymentName)
|
payment := getPayment(owner, paymentName)
|
||||||
if payment == nil {
|
if payment == nil {
|
||||||
return nil, fmt.Errorf("the payment: %s does not exist", paymentName)
|
err = fmt.Errorf("the payment: %s does not exist", paymentName)
|
||||||
|
return nil, err, pProvider.GetResponseError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
product := getProduct(owner, productName)
|
product := getProduct(owner, productName)
|
||||||
if product == nil {
|
if product == nil {
|
||||||
return nil, fmt.Errorf("the product: %s does not exist", productName)
|
err = fmt.Errorf("the product: %s does not exist", productName)
|
||||||
}
|
return payment, err, pProvider.GetResponseError(err)
|
||||||
|
|
||||||
provider, err := product.getProvider(providerName)
|
|
||||||
if err != nil {
|
|
||||||
return payment, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pProvider, cert, err := provider.getPaymentProvider()
|
|
||||||
if err != nil {
|
|
||||||
return payment, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
productDisplayName, paymentName, price, productName, providerName, err := pProvider.Notify(request, body, cert.AuthorityPublicKey)
|
productDisplayName, paymentName, price, productName, providerName, err := pProvider.Notify(request, body, cert.AuthorityPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return payment, err
|
return payment, err, pProvider.GetResponseError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if productDisplayName != "" && productDisplayName != product.DisplayName {
|
if productDisplayName != "" && productDisplayName != product.DisplayName {
|
||||||
return nil, fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", productDisplayName, product.DisplayName)
|
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", productDisplayName, product.DisplayName)
|
||||||
|
return payment, err, pProvider.GetResponseError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if price != product.Price {
|
if price != product.Price {
|
||||||
return nil, fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", price, product.Price)
|
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", price, product.Price)
|
||||||
|
return payment, err, pProvider.GetResponseError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return payment, nil
|
err = nil
|
||||||
|
return payment, err, pProvider.GetResponseError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string) bool {
|
func NotifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string) (error, string) {
|
||||||
payment, err := notifyPayment(request, body, owner, providerName, productName, paymentName)
|
payment, err, errorResponse := notifyPayment(request, body, owner, providerName, productName, paymentName)
|
||||||
|
|
||||||
if payment != nil {
|
if payment != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
payment.State = "Error"
|
payment.State = "Error"
|
||||||
@@ -203,8 +204,7 @@ func NotifyPayment(request *http.Request, body []byte, owner string, providerNam
|
|||||||
UpdatePayment(payment.GetId(), payment)
|
UpdatePayment(payment.GetId(), payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := err == nil
|
return err, errorResponse
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func invoicePayment(payment *Payment) (string, error) {
|
func invoicePayment(payment *Payment) (string, error) {
|
||||||
|
@@ -15,8 +15,6 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
@@ -65,30 +63,6 @@ func (p *Permission) GetId() string {
|
|||||||
return util.GetId(p.Owner, p.Name)
|
return util.GetId(p.Owner, p.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PermissionRule) GetRequest(adapterName string, permissionId string) ([]interface{}, error) {
|
|
||||||
request := []interface{}{p.V0, p.V1, p.V2}
|
|
||||||
|
|
||||||
if p.V3 != "" {
|
|
||||||
request = append(request, p.V3)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.V4 != "" {
|
|
||||||
request = append(request, p.V4)
|
|
||||||
}
|
|
||||||
|
|
||||||
if adapterName == builtInAdapter {
|
|
||||||
if p.V5 != "" {
|
|
||||||
return nil, fmt.Errorf("too many parameters. The maximum parameter number cannot exceed %d", builtInAvailableField)
|
|
||||||
}
|
|
||||||
return request, nil
|
|
||||||
} else {
|
|
||||||
if p.V5 != "" {
|
|
||||||
request = append(request, p.V5)
|
|
||||||
}
|
|
||||||
return request, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPermissionCount(owner, field, value string) int {
|
func GetPermissionCount(owner, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Permission{})
|
count, err := session.Count(&Permission{})
|
||||||
@@ -239,7 +213,7 @@ func DeletePermission(permission *Permission) bool {
|
|||||||
|
|
||||||
func GetPermissionsByUser(userId string) []*Permission {
|
func GetPermissionsByUser(userId string) []*Permission {
|
||||||
permissions := []*Permission{}
|
permissions := []*Permission{}
|
||||||
err := adapter.Engine.Where("users like ?", "%"+userId+"%").Find(&permissions)
|
err := adapter.Engine.Where("users like ?", "%"+userId+"\"%").Find(&permissions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -253,7 +227,17 @@ func GetPermissionsByUser(userId string) []*Permission {
|
|||||||
|
|
||||||
func GetPermissionsByRole(roleId string) []*Permission {
|
func GetPermissionsByRole(roleId string) []*Permission {
|
||||||
permissions := []*Permission{}
|
permissions := []*Permission{}
|
||||||
err := adapter.Engine.Where("roles like ?", "%"+roleId+"%").Find(&permissions)
|
err := adapter.Engine.Where("roles like ?", "%"+roleId+"\"%").Find(&permissions)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPermissionsByResource(resourceId string) []*Permission {
|
||||||
|
permissions := []*Permission{}
|
||||||
|
err := adapter.Engine.Where("resources like ?", "%"+resourceId+"\"%").Find(&permissions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -271,6 +255,16 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
|
|||||||
return permissions
|
return permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPermissionsByModel(owner string, model string) []*Permission {
|
||||||
|
permissions := []*Permission{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Model: model})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions
|
||||||
|
}
|
||||||
|
|
||||||
func ContainsAsterisk(userId string, users []string) bool {
|
func ContainsAsterisk(userId string, users []string) bool {
|
||||||
containsAsterisk := false
|
containsAsterisk := false
|
||||||
group, _ := util.GetOwnerAndNameFromId(userId)
|
group, _ := util.GetOwnerAndNameFromId(userId)
|
||||||
|
@@ -62,7 +62,11 @@ func getEnforcer(permission *Permission) *casbin.Enforcer {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
enforcer.InitWithModelAndAdapter(m, nil)
|
err = enforcer.InitWithModelAndAdapter(m, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
enforcer.SetAdapter(adapter)
|
enforcer.SetAdapter(adapter)
|
||||||
|
|
||||||
policyFilter := xormadapter.Filter{
|
policyFilter := xormadapter.Filter{
|
||||||
@@ -118,35 +122,53 @@ func getPolicies(permission *Permission) [][]string {
|
|||||||
return policies
|
return policies
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRolesInRole(roleId string, visited map[string]struct{}) []*Role {
|
||||||
|
role := GetRole(roleId)
|
||||||
|
if role == nil {
|
||||||
|
return []*Role{}
|
||||||
|
}
|
||||||
|
visited[roleId] = struct{}{}
|
||||||
|
|
||||||
|
roles := []*Role{role}
|
||||||
|
for _, subRole := range role.Roles {
|
||||||
|
if _, ok := visited[subRole]; !ok {
|
||||||
|
roles = append(roles, getRolesInRole(subRole, visited)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
func getGroupingPolicies(permission *Permission) [][]string {
|
func getGroupingPolicies(permission *Permission) [][]string {
|
||||||
var groupingPolicies [][]string
|
var groupingPolicies [][]string
|
||||||
|
|
||||||
domainExist := len(permission.Domains) > 0
|
domainExist := len(permission.Domains) > 0
|
||||||
permissionId := permission.GetId()
|
permissionId := permission.GetId()
|
||||||
|
|
||||||
for _, role := range permission.Roles {
|
for _, roleId := range permission.Roles {
|
||||||
roleObj := GetRole(role)
|
visited := map[string]struct{}{}
|
||||||
if roleObj == nil {
|
rolesInRole := getRolesInRole(roleId, visited)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subUser := range roleObj.Users {
|
for _, role := range rolesInRole {
|
||||||
if domainExist {
|
roleId := role.GetId()
|
||||||
for _, domain := range permission.Domains {
|
for _, subUser := range role.Users {
|
||||||
groupingPolicies = append(groupingPolicies, []string{subUser, role, domain, "", "", permissionId})
|
if domainExist {
|
||||||
|
for _, domain := range permission.Domains {
|
||||||
|
groupingPolicies = append(groupingPolicies, []string{subUser, roleId, domain, "", "", permissionId})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
groupingPolicies = append(groupingPolicies, []string{subUser, roleId, "", "", "", permissionId})
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
groupingPolicies = append(groupingPolicies, []string{subUser, role, "", "", "", permissionId})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, subRole := range roleObj.Roles {
|
for _, subRole := range role.Roles {
|
||||||
if domainExist {
|
if domainExist {
|
||||||
for _, domain := range permission.Domains {
|
for _, domain := range permission.Domains {
|
||||||
groupingPolicies = append(groupingPolicies, []string{subRole, role, domain, "", "", permissionId})
|
groupingPolicies = append(groupingPolicies, []string{subRole, roleId, domain, "", "", permissionId})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
groupingPolicies = append(groupingPolicies, []string{subRole, roleId, "", "", "", permissionId})
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
groupingPolicies = append(groupingPolicies, []string{subRole, role, "", "", "", permissionId})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,28 +220,23 @@ func removePolicies(permission *Permission) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Enforce(permissionRule *PermissionRule) bool {
|
type CasbinRequest = []interface{}
|
||||||
permission := GetPermission(permissionRule.Id)
|
|
||||||
|
func Enforce(permissionId string, request *CasbinRequest) bool {
|
||||||
|
permission := GetPermission(permissionId)
|
||||||
enforcer := getEnforcer(permission)
|
enforcer := getEnforcer(permission)
|
||||||
|
|
||||||
request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
|
allow, err := enforcer.Enforce(*request...)
|
||||||
|
|
||||||
allow, err := enforcer.Enforce(request...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return allow
|
return allow
|
||||||
}
|
}
|
||||||
|
|
||||||
func BatchEnforce(permissionRules []PermissionRule) []bool {
|
func BatchEnforce(permissionId string, requests *[]CasbinRequest) []bool {
|
||||||
var requests [][]interface{}
|
permission := GetPermission(permissionId)
|
||||||
for _, permissionRule := range permissionRules {
|
|
||||||
request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
|
|
||||||
requests = append(requests, request)
|
|
||||||
}
|
|
||||||
permission := GetPermission(permissionRules[0].Id)
|
|
||||||
enforcer := getEnforcer(permission)
|
enforcer := getEnforcer(permission)
|
||||||
allow, err := enforcer.BatchEnforce(requests)
|
allow, err := enforcer.BatchEnforce(*requests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
145
object/plan.go
Normal file
145
object/plan.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/xorm-io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Plan 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"`
|
||||||
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
|
PricePerMonth float64 `json:"pricePerMonth"`
|
||||||
|
PricePerYear float64 `json:"pricePerYear"`
|
||||||
|
Currency string `xorm:"varchar(100)" json:"currency"`
|
||||||
|
IsEnabled bool `json:"isEnabled"`
|
||||||
|
|
||||||
|
Role string `xorm:"varchar(100)" json:"role"`
|
||||||
|
Options []string `xorm:"-" json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlanCount(owner, field, value string) int {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&Plan{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlans(owner string) []*Plan {
|
||||||
|
plans := []*Plan{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&plans, &Plan{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return plans
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginatedPlans(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Plan {
|
||||||
|
plans := []*Plan{}
|
||||||
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Find(&plans)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return plans
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPlan(owner, name string) *Plan {
|
||||||
|
if owner == "" || name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
plan := Plan{Owner: owner, Name: name}
|
||||||
|
existed, err := adapter.Engine.Get(&plan)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if existed {
|
||||||
|
return &plan
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlan(id string) *Plan {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getPlan(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePlan(id string, plan *Plan) bool {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if getPlan(owner, name) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(plan)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddPlan(plan *Plan) bool {
|
||||||
|
affected, err := adapter.Engine.Insert(plan)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeletePlan(plan *Plan) bool {
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{plan.Owner, plan.Name}).Delete(plan)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (plan *Plan) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", plan.Owner, plan.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Subscribe(owner string, user string, plan string, pricing string) *Subscription {
|
||||||
|
selectedPricing := GetPricing(fmt.Sprintf("%s/%s", owner, pricing))
|
||||||
|
|
||||||
|
valid := selectedPricing != nil && selectedPricing.IsEnabled
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
planBelongToPricing := selectedPricing.HasPlan(owner, plan)
|
||||||
|
|
||||||
|
if planBelongToPricing {
|
||||||
|
newSubscription := NewSubscription(owner, user, plan, selectedPricing.TrialDuration)
|
||||||
|
affected := AddSubscription(newSubscription)
|
||||||
|
|
||||||
|
if affected {
|
||||||
|
return newSubscription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
147
object/pricing.go
Normal file
147
object/pricing.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// Copyright 2023 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/casdoor/casdoor/util"
|
||||||
|
"github.com/xorm-io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pricing 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"`
|
||||||
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
|
||||||
|
Plans []string `xorm:"mediumtext" json:"plans"`
|
||||||
|
IsEnabled bool `json:"isEnabled"`
|
||||||
|
HasTrial bool `json:"hasTrial"`
|
||||||
|
TrialDuration int `json:"trialDuration"`
|
||||||
|
Application string `xorm:"varchar(100)" json:"application"`
|
||||||
|
|
||||||
|
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
||||||
|
Approver string `xorm:"varchar(100)" json:"approver"`
|
||||||
|
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
||||||
|
|
||||||
|
State string `xorm:"varchar(100)" json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPricingCount(owner, field, value string) int {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&Pricing{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPricings(owner string) []*Pricing {
|
||||||
|
pricings := []*Pricing{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&pricings, &Pricing{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return pricings
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginatedPricings(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Pricing {
|
||||||
|
pricings := []*Pricing{}
|
||||||
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Find(&pricings)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return pricings
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPricing(owner, name string) *Pricing {
|
||||||
|
if owner == "" || name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pricing := Pricing{Owner: owner, Name: name}
|
||||||
|
existed, err := adapter.Engine.Get(&pricing)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if existed {
|
||||||
|
return &pricing
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPricing(id string) *Pricing {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getPricing(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePricing(id string, pricing *Pricing) bool {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if getPricing(owner, name) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(pricing)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddPricing(pricing *Pricing) bool {
|
||||||
|
affected, err := adapter.Engine.Insert(pricing)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeletePricing(pricing *Pricing) bool {
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{pricing.Owner, pricing.Name}).Delete(pricing)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pricing *Pricing) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", pricing.Owner, pricing.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pricing *Pricing) HasPlan(owner string, plan string) bool {
|
||||||
|
selectedPlan := GetPlan(fmt.Sprintf("%s/%s", owner, plan))
|
||||||
|
|
||||||
|
if selectedPlan == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
result := false
|
||||||
|
|
||||||
|
for _, pricingPlan := range pricing.Plans {
|
||||||
|
if strings.Contains(pricingPlan, selectedPlan.Name) {
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
@@ -30,7 +30,7 @@ func TestProduct(t *testing.T) {
|
|||||||
product := GetProduct("admin/product_123")
|
product := GetProduct("admin/product_123")
|
||||||
provider := getProvider(product.Owner, "provider_pay_alipay")
|
provider := getProvider(product.Owner, "provider_pay_alipay")
|
||||||
cert := getCert(product.Owner, "cert-pay-alipay")
|
cert := getCert(product.Owner, "cert-pay-alipay")
|
||||||
pProvider, err := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
|
pProvider, err := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, provider.ClientSecret2, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
129
object/prometheus.go
Normal file
129
object/prometheus.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
"github.com/prometheus/client_model/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PrometheusInfo struct {
|
||||||
|
ApiThroughput []GaugeVecInfo `json:"apiThroughput"`
|
||||||
|
ApiLatency []HistogramVecInfo `json:"apiLatency"`
|
||||||
|
TotalThroughput float64 `json:"totalThroughput"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeVecInfo struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Throughput float64 `json:"throughput"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HistogramVecInfo struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Count uint64 `json:"count"`
|
||||||
|
Latency string `json:"latency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ApiThroughput = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "casdoor_api_throughput",
|
||||||
|
Help: "The throughput of each api access",
|
||||||
|
}, []string{"path", "method"})
|
||||||
|
|
||||||
|
ApiLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
|
Name: "casdoor_api_latency",
|
||||||
|
Help: "API processing latency in milliseconds",
|
||||||
|
}, []string{"path", "method"})
|
||||||
|
|
||||||
|
CpuUsage = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "casdoor_cpu_usage",
|
||||||
|
Help: "Casdoor cpu usage",
|
||||||
|
}, []string{"cpuNum"})
|
||||||
|
|
||||||
|
MemoryUsage = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Name: "casdoor_memory_usage",
|
||||||
|
Help: "Casdoor memory usage in Byte",
|
||||||
|
}, []string{"type"})
|
||||||
|
|
||||||
|
TotalThroughput = promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "casdoor_total_throughput",
|
||||||
|
Help: "The total throughput of casdoor",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
func ClearThroughputPerSecond() {
|
||||||
|
// Clear the throughput every second
|
||||||
|
ticker := time.NewTicker(time.Second)
|
||||||
|
for range ticker.C {
|
||||||
|
ApiThroughput.Reset()
|
||||||
|
TotalThroughput.Set(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPrometheusInfo() (*PrometheusInfo, error) {
|
||||||
|
res := &PrometheusInfo{}
|
||||||
|
metricFamilies, err := prometheus.DefaultGatherer.Gather()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, metricFamily := range metricFamilies {
|
||||||
|
switch metricFamily.GetName() {
|
||||||
|
case "casdoor_api_throughput":
|
||||||
|
res.ApiThroughput = getGaugeVecInfo(metricFamily)
|
||||||
|
case "casdoor_api_latency":
|
||||||
|
res.ApiLatency = getHistogramVecInfo(metricFamily)
|
||||||
|
case "casdoor_total_throughput":
|
||||||
|
res.TotalThroughput = metricFamily.GetMetric()[0].GetGauge().GetValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHistogramVecInfo(metricFamily *io_prometheus_client.MetricFamily) []HistogramVecInfo {
|
||||||
|
var histogramVecInfos []HistogramVecInfo
|
||||||
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
|
sampleCount := metric.GetHistogram().GetSampleCount()
|
||||||
|
sampleSum := metric.GetHistogram().GetSampleSum()
|
||||||
|
latency := sampleSum / float64(sampleCount)
|
||||||
|
histogramVecInfo := HistogramVecInfo{
|
||||||
|
Method: metric.Label[0].GetValue(),
|
||||||
|
Name: metric.Label[1].GetValue(),
|
||||||
|
Count: sampleCount,
|
||||||
|
Latency: fmt.Sprintf("%.3f", latency),
|
||||||
|
}
|
||||||
|
histogramVecInfos = append(histogramVecInfos, histogramVecInfo)
|
||||||
|
}
|
||||||
|
return histogramVecInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGaugeVecInfo(metricFamily *io_prometheus_client.MetricFamily) []GaugeVecInfo {
|
||||||
|
var counterVecInfos []GaugeVecInfo
|
||||||
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
|
counterVecInfo := GaugeVecInfo{
|
||||||
|
Method: metric.Label[0].GetValue(),
|
||||||
|
Name: metric.Label[1].GetValue(),
|
||||||
|
Throughput: metric.Gauge.GetValue(),
|
||||||
|
}
|
||||||
|
counterVecInfos = append(counterVecInfos, counterVecInfo)
|
||||||
|
}
|
||||||
|
return counterVecInfos
|
||||||
|
}
|
@@ -70,7 +70,11 @@ type Provider struct {
|
|||||||
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"`
|
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMaskedProvider(provider *Provider) *Provider {
|
func GetMaskedProvider(provider *Provider, isMaskEnabled bool) *Provider {
|
||||||
|
if !isMaskEnabled {
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -78,16 +82,23 @@ func GetMaskedProvider(provider *Provider) *Provider {
|
|||||||
if provider.ClientSecret != "" {
|
if provider.ClientSecret != "" {
|
||||||
provider.ClientSecret = "***"
|
provider.ClientSecret = "***"
|
||||||
}
|
}
|
||||||
if provider.ClientSecret2 != "" {
|
|
||||||
provider.ClientSecret2 = "***"
|
if provider.Category != "Email" {
|
||||||
|
if provider.ClientSecret2 != "" {
|
||||||
|
provider.ClientSecret2 = "***"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider
|
return provider
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMaskedProviders(providers []*Provider) []*Provider {
|
func GetMaskedProviders(providers []*Provider, isMaskEnabled bool) []*Provider {
|
||||||
|
if !isMaskEnabled {
|
||||||
|
return providers
|
||||||
|
}
|
||||||
|
|
||||||
for _, provider := range providers {
|
for _, provider := range providers {
|
||||||
provider = GetMaskedProvider(provider)
|
provider = GetMaskedProvider(provider, isMaskEnabled)
|
||||||
}
|
}
|
||||||
return providers
|
return providers
|
||||||
}
|
}
|
||||||
@@ -177,8 +188,8 @@ func GetProvider(id string) *Provider {
|
|||||||
return getProvider(owner, name)
|
return getProvider(owner, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultCaptchaProvider() *Provider {
|
func getDefaultAiProvider() *Provider {
|
||||||
provider := Provider{Owner: "admin", Category: "Captcha"}
|
provider := Provider{Owner: "admin", Category: "AI"}
|
||||||
existed, err := adapter.Engine.Get(&provider)
|
existed, err := adapter.Engine.Get(&provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -263,7 +274,7 @@ func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pProvider, err := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, p.ClientId2)
|
pProvider, err := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.Certificate, p.ClientSecret2, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, p.ClientId2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cert, err
|
return nil, cert, err
|
||||||
}
|
}
|
||||||
@@ -307,7 +318,7 @@ func GetCaptchaProviderByApplication(applicationId, isCurrentProvider, lang stri
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if provider.Provider.Category == "Captcha" {
|
if provider.Provider.Category == "Captcha" {
|
||||||
return GetCaptchaProviderByOwnerName(fmt.Sprintf("%s/%s", provider.Provider.Owner, provider.Provider.Name), lang)
|
return GetCaptchaProviderByOwnerName(util.GetId(provider.Provider.Owner, provider.Provider.Name), lang)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@@ -47,7 +47,8 @@ type Record struct {
|
|||||||
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
|
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
|
||||||
Action string `xorm:"varchar(1000)" json:"action"`
|
Action string `xorm:"varchar(1000)" json:"action"`
|
||||||
|
|
||||||
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
Object string `xorm:"-" json:"object"`
|
||||||
|
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
||||||
|
|
||||||
IsTriggered bool `json:"isTriggered"`
|
IsTriggered bool `json:"isTriggered"`
|
||||||
}
|
}
|
||||||
@@ -60,6 +61,11 @@ func NewRecord(ctx *context.Context) *Record {
|
|||||||
requestUri = requestUri[0:1000]
|
requestUri = requestUri[0:1000]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object := ""
|
||||||
|
if ctx.Input.RequestBody != nil && len(ctx.Input.RequestBody) != 0 {
|
||||||
|
object = string(ctx.Input.RequestBody)
|
||||||
|
}
|
||||||
|
|
||||||
record := Record{
|
record := Record{
|
||||||
Name: util.GenerateId(),
|
Name: util.GenerateId(),
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
@@ -68,6 +74,7 @@ func NewRecord(ctx *context.Context) *Record {
|
|||||||
Method: ctx.Request.Method,
|
Method: ctx.Request.Method,
|
||||||
RequestUri: requestUri,
|
RequestUri: requestUri,
|
||||||
Action: action,
|
Action: action,
|
||||||
|
Object: object,
|
||||||
IsTriggered: false,
|
IsTriggered: false,
|
||||||
}
|
}
|
||||||
return &record
|
return &record
|
||||||
@@ -159,7 +166,7 @@ func SendWebhooks(record *Record) error {
|
|||||||
|
|
||||||
if matched {
|
if matched {
|
||||||
if webhook.IsUserExtended {
|
if webhook.IsUserExtended {
|
||||||
user := getUser(record.Organization, record.User)
|
user := GetMaskedUser(getUser(record.Organization, record.User))
|
||||||
record.ExtendedUser = user
|
record.ExtendedUser = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -94,10 +94,25 @@ func UpdateRole(id string, role *Role) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visited := map[string]struct{}{}
|
||||||
|
|
||||||
permissions := GetPermissionsByRole(id)
|
permissions := GetPermissionsByRole(id)
|
||||||
for _, permission := range permissions {
|
for _, permission := range permissions {
|
||||||
removeGroupingPolicies(permission)
|
removeGroupingPolicies(permission)
|
||||||
removePolicies(permission)
|
removePolicies(permission)
|
||||||
|
visited[permission.GetId()] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ancestorRoles := GetAncestorRoles(id)
|
||||||
|
for _, r := range ancestorRoles {
|
||||||
|
permissions := GetPermissionsByRole(r.GetId())
|
||||||
|
for _, permission := range permissions {
|
||||||
|
permissionId := permission.GetId()
|
||||||
|
if _, ok := visited[permissionId]; !ok {
|
||||||
|
removeGroupingPolicies(permission)
|
||||||
|
visited[permissionId] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if name != role.Name {
|
if name != role.Name {
|
||||||
@@ -112,11 +127,25 @@ func UpdateRole(id string, role *Role) bool {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visited = map[string]struct{}{}
|
||||||
newRoleID := role.GetId()
|
newRoleID := role.GetId()
|
||||||
permissions = GetPermissionsByRole(newRoleID)
|
permissions = GetPermissionsByRole(newRoleID)
|
||||||
for _, permission := range permissions {
|
for _, permission := range permissions {
|
||||||
addGroupingPolicies(permission)
|
addGroupingPolicies(permission)
|
||||||
addPolicies(permission)
|
addPolicies(permission)
|
||||||
|
visited[permission.GetId()] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ancestorRoles = GetAncestorRoles(newRoleID)
|
||||||
|
for _, r := range ancestorRoles {
|
||||||
|
permissions := GetPermissionsByRole(r.GetId())
|
||||||
|
for _, permission := range permissions {
|
||||||
|
permissionId := permission.GetId()
|
||||||
|
if _, ok := visited[permissionId]; !ok {
|
||||||
|
addGroupingPolicies(permission)
|
||||||
|
visited[permissionId] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return affected != 0
|
return affected != 0
|
||||||
@@ -153,7 +182,7 @@ func (role *Role) GetId() string {
|
|||||||
|
|
||||||
func GetRolesByUser(userId string) []*Role {
|
func GetRolesByUser(userId string) []*Role {
|
||||||
roles := []*Role{}
|
roles := []*Role{}
|
||||||
err := adapter.Engine.Where("users like ?", "%"+userId+"%").Find(&roles)
|
err := adapter.Engine.Where("users like ?", "%"+userId+"\"%").Find(&roles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -221,3 +250,64 @@ func GetMaskedRoles(roles []*Role) []*Role {
|
|||||||
|
|
||||||
return roles
|
return roles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRolesByNamePrefix(owner string, prefix string) []*Role {
|
||||||
|
roles := []*Role{}
|
||||||
|
err := adapter.Engine.Where("owner=? and name like ?", owner, prefix+"%").Find(&roles)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAncestorRoles(roleId string) []*Role {
|
||||||
|
var (
|
||||||
|
result []*Role
|
||||||
|
roleMap = make(map[string]*Role)
|
||||||
|
visited = make(map[string]bool)
|
||||||
|
)
|
||||||
|
|
||||||
|
owner, _ := util.GetOwnerAndNameFromIdNoCheck(roleId)
|
||||||
|
|
||||||
|
allRoles := GetRoles(owner)
|
||||||
|
for _, r := range allRoles {
|
||||||
|
roleMap[r.GetId()] = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, find all the roles that contain father roles
|
||||||
|
for _, r := range allRoles {
|
||||||
|
isContain, ok := visited[r.GetId()]
|
||||||
|
if isContain {
|
||||||
|
result = append(result, r)
|
||||||
|
} else if !ok {
|
||||||
|
rId := r.GetId()
|
||||||
|
visited[rId] = containsRole(r, roleId, roleMap, visited)
|
||||||
|
if visited[rId] {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// containsRole is a helper function to check if a slice of roles contains a specific roleId
|
||||||
|
func containsRole(role *Role, roleId string, roleMap map[string]*Role, visited map[string]bool) bool {
|
||||||
|
if isContain, ok := visited[role.GetId()]; ok {
|
||||||
|
return isContain
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subRole := range role.Roles {
|
||||||
|
if subRole == roleId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
r, ok := roleMap[subRole]
|
||||||
|
if ok && containsRole(r, roleId, roleMap, visited) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
154
object/subscription.go
Normal file
154
object/subscription.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// Copyright 2023 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"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/xorm-io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultStatus = "Pending"
|
||||||
|
|
||||||
|
type Subscription 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"`
|
||||||
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
|
||||||
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
|
Plan string `xorm:"varchar(100)" json:"plan"`
|
||||||
|
|
||||||
|
StartDate time.Time `json:"startDate"`
|
||||||
|
EndDate time.Time `json:"endDate"`
|
||||||
|
|
||||||
|
User string `xorm:"mediumtext" json:"user"`
|
||||||
|
|
||||||
|
IsEnabled bool `json:"isEnabled"`
|
||||||
|
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
||||||
|
Approver string `xorm:"varchar(100)" json:"approver"`
|
||||||
|
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
||||||
|
|
||||||
|
State string `xorm:"varchar(100)" json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubscription(owner string, user string, plan string, duration int) *Subscription {
|
||||||
|
id := util.GenerateId()[:6]
|
||||||
|
return &Subscription{
|
||||||
|
Name: "Subscription_" + id,
|
||||||
|
DisplayName: "New Subscription - " + id,
|
||||||
|
Owner: owner,
|
||||||
|
User: owner + "/" + user,
|
||||||
|
Plan: owner + "/" + plan,
|
||||||
|
CreatedTime: util.GetCurrentTime(),
|
||||||
|
State: defaultStatus,
|
||||||
|
Duration: duration,
|
||||||
|
StartDate: time.Now(),
|
||||||
|
EndDate: time.Now().AddDate(0, 0, duration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscriptionCount(owner, field, value string) int {
|
||||||
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
|
count, err := session.Count(&Subscription{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscriptions(owner string) []*Subscription {
|
||||||
|
subscriptions := []*Subscription{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&subscriptions, &Subscription{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscriptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationSubscriptions(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Subscription {
|
||||||
|
subscriptions := []*Subscription{}
|
||||||
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
|
err := session.Find(&subscriptions)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscriptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubscription(owner string, name string) *Subscription {
|
||||||
|
if owner == "" || name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription := Subscription{Owner: owner, Name: name}
|
||||||
|
existed, err := adapter.Engine.Get(&subscription)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
return &subscription
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSubscription(id string) *Subscription {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getSubscription(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateSubscription(id string, subscription *Subscription) bool {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if getSubscription(owner, name) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(subscription)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSubscription(subscription *Subscription) bool {
|
||||||
|
affected, err := adapter.Engine.Insert(subscription)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSubscription(subscription *Subscription) bool {
|
||||||
|
affected, err := adapter.Engine.ID(core.PK{subscription.Owner, subscription.Name}).Delete(&Subscription{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (subscription *Subscription) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", subscription.Owner, subscription.Name)
|
||||||
|
}
|
@@ -55,9 +55,9 @@ type Syncer struct {
|
|||||||
Adapter *Adapter `xorm:"-" json:"-"`
|
Adapter *Adapter `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSyncerCount(owner, field, value string) int {
|
func GetSyncerCount(owner, organization, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Syncer{})
|
count, err := session.Count(&Syncer{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -75,10 +75,20 @@ func GetSyncers(owner string) []*Syncer {
|
|||||||
return syncers
|
return syncers
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationSyncers(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Syncer {
|
func GetOrganizationSyncers(owner, organization string) []*Syncer {
|
||||||
|
syncers := []*Syncer{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&syncers, &Syncer{Owner: owner, Organization: organization})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return syncers
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPaginationSyncers(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Syncer {
|
||||||
syncers := []*Syncer{}
|
syncers := []*Syncer{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&syncers)
|
err := session.Find(&syncers, &Syncer{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -91,9 +91,9 @@ type IntrospectionResponse struct {
|
|||||||
Jti string `json:"jti,omitempty"`
|
Jti string `json:"jti,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTokenCount(owner, field, value string) int {
|
func GetTokenCount(owner, organization, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Token{})
|
count, err := session.Count(&Token{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -101,9 +101,9 @@ func GetTokenCount(owner, field, value string) int {
|
|||||||
return int(count)
|
return int(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTokens(owner string) []*Token {
|
func GetTokens(owner string, organization string) []*Token {
|
||||||
tokens := []*Token{}
|
tokens := []*Token{}
|
||||||
err := adapter.Engine.Desc("created_time").Find(&tokens, &Token{Owner: owner})
|
err := adapter.Engine.Desc("created_time").Find(&tokens, &Token{Owner: owner, Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -111,10 +111,10 @@ func GetTokens(owner string) []*Token {
|
|||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationTokens(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Token {
|
func GetPaginationTokens(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Token {
|
||||||
tokens := []*Token{}
|
tokens := []*Token{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&tokens)
|
err := session.Find(&tokens, &Token{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -224,13 +224,16 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
|
|||||||
nowTime := time.Now()
|
nowTime := time.Now()
|
||||||
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
||||||
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
||||||
|
if application.RefreshExpireInHours == 0 {
|
||||||
|
refreshExpireTime = expireTime
|
||||||
|
}
|
||||||
|
|
||||||
user = refineUser(user)
|
user = refineUser(user)
|
||||||
|
|
||||||
_, originBackend := getOriginFromHost(host)
|
_, originBackend := getOriginFromHost(host)
|
||||||
|
|
||||||
name := util.GenerateId()
|
name := util.GenerateId()
|
||||||
jti := fmt.Sprintf("%s/%s", application.Owner, name)
|
jti := util.GetId(application.Owner, name)
|
||||||
|
|
||||||
claims := Claims{
|
claims := Claims{
|
||||||
User: user,
|
User: user,
|
||||||
|
@@ -41,6 +41,7 @@ type User struct {
|
|||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
Password string `xorm:"varchar(100)" json:"password"`
|
Password string `xorm:"varchar(100)" json:"password"`
|
||||||
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
|
||||||
|
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
|
||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
FirstName string `xorm:"varchar(100)" json:"firstName"`
|
FirstName string `xorm:"varchar(100)" json:"firstName"`
|
||||||
LastName string `xorm:"varchar(100)" json:"lastName"`
|
LastName string `xorm:"varchar(100)" json:"lastName"`
|
||||||
@@ -157,6 +158,7 @@ type User struct {
|
|||||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||||
|
|
||||||
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
||||||
|
MultiFactorAuths []*MfaProps `json:"multiFactorAuths"`
|
||||||
|
|
||||||
Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
|
Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
|
||||||
Properties map[string]string `json:"properties"`
|
Properties map[string]string `json:"properties"`
|
||||||
@@ -249,6 +251,16 @@ func GetUsers(owner string) []*User {
|
|||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetUsersByTag(owner string, tag string) []*User {
|
||||||
|
users := []*User{}
|
||||||
|
err := adapter.Engine.Desc("created_time").Find(&users, &User{Owner: owner, Tag: tag})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
|
||||||
func GetSortedUsers(owner string, sorter string, limit int) []*User {
|
func GetSortedUsers(owner string, sorter string, limit int) []*User {
|
||||||
users := []*User{}
|
users := []*User{}
|
||||||
err := adapter.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &User{Owner: owner})
|
err := adapter.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &User{Owner: owner})
|
||||||
@@ -401,6 +413,12 @@ func GetMaskedUser(user *User) *User {
|
|||||||
manageAccount.Password = "***"
|
manageAccount.Password = "***"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.MultiFactorAuths != nil {
|
||||||
|
for i, props := range user.MultiFactorAuths {
|
||||||
|
user.MultiFactorAuths[i] = GetMaskedProps(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +443,7 @@ func GetLastUser(owner string) *User {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) bool {
|
func UpdateUser(id string, user *User, columns []string, isAdmin bool) bool {
|
||||||
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
|
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
|
||||||
oldUser := getUser(owner, name)
|
oldUser := getUser(owner, name)
|
||||||
if oldUser == nil {
|
if oldUser == nil {
|
||||||
@@ -454,9 +472,16 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
|||||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
"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",
|
||||||
|
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||||
|
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||||
|
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||||
|
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
|
||||||
|
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
|
||||||
|
"spotify", "strava", "stripe", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
|
||||||
|
"yammer", "yandex", "zoom", "custom",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isGlobalAdmin {
|
if isAdmin {
|
||||||
columns = append(columns, "name", "email", "phone", "country_code")
|
columns = append(columns, "name", "email", "phone", "country_code")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,3 +758,35 @@ func (user *User) refreshAvatar() bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) IsMfaEnabled() bool {
|
||||||
|
return len(user.MultiFactorAuths) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) GetPreferMfa(masked bool) *MfaProps {
|
||||||
|
if len(user.MultiFactorAuths) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if masked {
|
||||||
|
if len(user.MultiFactorAuths) == 1 {
|
||||||
|
return GetMaskedProps(user.MultiFactorAuths[0])
|
||||||
|
}
|
||||||
|
for _, v := range user.MultiFactorAuths {
|
||||||
|
if v.IsPreferred {
|
||||||
|
return GetMaskedProps(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GetMaskedProps(user.MultiFactorAuths[0])
|
||||||
|
} else {
|
||||||
|
if len(user.MultiFactorAuths) == 1 {
|
||||||
|
return user.MultiFactorAuths[0]
|
||||||
|
}
|
||||||
|
for _, v := range user.MultiFactorAuths {
|
||||||
|
if v.IsPreferred {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user.MultiFactorAuths[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -35,5 +35,6 @@ func (user *User) UpdateUserPassword(organization *Organization) {
|
|||||||
if credManager != nil {
|
if credManager != nil {
|
||||||
hashedPassword := credManager.GetHashedPassword(user.Password, user.PasswordSalt, organization.PasswordSalt)
|
hashedPassword := credManager.GetHashedPassword(user.Password, user.PasswordSalt, organization.PasswordSalt)
|
||||||
user.Password = hashedPassword
|
user.Password = hashedPassword
|
||||||
|
user.PasswordType = organization.PasswordType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -76,13 +77,17 @@ func GetUserByFields(organization string, field string) *User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SetUserField(user *User, field string, value string) bool {
|
func SetUserField(user *User, field string, value string) bool {
|
||||||
|
bean := make(map[string]interface{})
|
||||||
if field == "password" {
|
if field == "password" {
|
||||||
organization := GetOrganizationByUser(user)
|
organization := GetOrganizationByUser(user)
|
||||||
user.UpdateUserPassword(organization)
|
user.UpdateUserPassword(organization)
|
||||||
value = user.Password
|
bean[strings.ToLower(field)] = user.Password
|
||||||
|
bean["password_type"] = user.PasswordType
|
||||||
|
} else {
|
||||||
|
bean[strings.ToLower(field)] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(map[string]interface{}{strings.ToLower(field): value})
|
affected, err := adapter.Engine.Table(user).ID(core.PK{user.Owner, user.Name}).Update(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -179,6 +184,123 @@ func ClearUserOAuthProperties(user *User, providerType string) bool {
|
|||||||
return affected != 0
|
return affected != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang string) (bool, string) {
|
||||||
|
organization := GetOrganizationByUser(oldUser)
|
||||||
|
var itemsChanged []*AccountItem
|
||||||
|
|
||||||
|
if oldUser.Owner != newUser.Owner {
|
||||||
|
item := GetAccountItemByName("Organization", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Name != newUser.Name {
|
||||||
|
item := GetAccountItemByName("Name", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Id != newUser.Id {
|
||||||
|
item := GetAccountItemByName("ID", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.DisplayName != newUser.DisplayName {
|
||||||
|
item := GetAccountItemByName("Display name", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Avatar != newUser.Avatar {
|
||||||
|
item := GetAccountItemByName("Avatar", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Type != newUser.Type {
|
||||||
|
item := GetAccountItemByName("User type", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
// The password is *** when not modified
|
||||||
|
if oldUser.Password != newUser.Password && newUser.Password != "***" {
|
||||||
|
item := GetAccountItemByName("Password", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Email != newUser.Email {
|
||||||
|
item := GetAccountItemByName("Email", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Phone != newUser.Phone {
|
||||||
|
item := GetAccountItemByName("Phone", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.CountryCode != newUser.CountryCode {
|
||||||
|
item := GetAccountItemByName("Country code", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Region != newUser.Region {
|
||||||
|
item := GetAccountItemByName("Country/Region", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Location != newUser.Location {
|
||||||
|
item := GetAccountItemByName("Location", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Affiliation != newUser.Affiliation {
|
||||||
|
item := GetAccountItemByName("Affiliation", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Title != newUser.Title {
|
||||||
|
item := GetAccountItemByName("Title", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Homepage != newUser.Homepage {
|
||||||
|
item := GetAccountItemByName("Homepage", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Bio != newUser.Bio {
|
||||||
|
item := GetAccountItemByName("Bio", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.Tag != newUser.Tag {
|
||||||
|
item := GetAccountItemByName("Tag", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.SignupApplication != newUser.SignupApplication {
|
||||||
|
item := GetAccountItemByName("Signup application", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserPropertiesJson, _ := json.Marshal(oldUser.Properties)
|
||||||
|
newUserPropertiesJson, _ := json.Marshal(newUser.Properties)
|
||||||
|
if string(oldUserPropertiesJson) != string(newUserPropertiesJson) {
|
||||||
|
item := GetAccountItemByName("Properties", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUserTwoFactorAuthJson, _ := json.Marshal(oldUser.MultiFactorAuths)
|
||||||
|
newUserTwoFactorAuthJson, _ := json.Marshal(newUser.MultiFactorAuths)
|
||||||
|
if string(oldUserTwoFactorAuthJson) != string(newUserTwoFactorAuthJson) {
|
||||||
|
item := GetAccountItemByName("Multi-factor authentication", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldUser.IsAdmin != newUser.IsAdmin {
|
||||||
|
item := GetAccountItemByName("Is admin", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
|
||||||
|
item := GetAccountItemByName("Is global admin", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsForbidden != newUser.IsForbidden {
|
||||||
|
item := GetAccountItemByName("Is forbidden", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
if oldUser.IsDeleted != newUser.IsDeleted {
|
||||||
|
item := GetAccountItemByName("Is deleted", organization)
|
||||||
|
itemsChanged = append(itemsChanged, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range itemsChanged {
|
||||||
|
if pass, err := CheckAccountItemModifyRule(itemsChanged[i], isAdmin, lang); !pass {
|
||||||
|
return pass, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) GetCountryCode(countryCode string) string {
|
func (user *User) GetCountryCode(countryCode string) string {
|
||||||
if countryCode != "" {
|
if countryCode != "" {
|
||||||
return countryCode
|
return countryCode
|
||||||
@@ -193,3 +315,11 @@ func (user *User) GetCountryCode(countryCode string) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) IsAdminUser() bool {
|
||||||
|
if user == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.IsAdmin || user.IsGlobalAdmin
|
||||||
|
}
|
||||||
|
@@ -33,10 +33,10 @@ type VerifyResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VerificationSuccess int = 0
|
VerificationSuccess = iota
|
||||||
wrongCodeError = 1
|
wrongCodeError
|
||||||
noRecordError = 2
|
noRecordError
|
||||||
timeoutError = 3
|
timeoutError
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@@ -42,9 +42,9 @@ type Webhook struct {
|
|||||||
IsEnabled bool `json:"isEnabled"`
|
IsEnabled bool `json:"isEnabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWebhookCount(owner, field, value string) int {
|
func GetWebhookCount(owner, organization, field, value string) int {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
count, err := session.Count(&Webhook{})
|
count, err := session.Count(&Webhook{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -52,9 +52,9 @@ func GetWebhookCount(owner, field, value string) int {
|
|||||||
return int(count)
|
return int(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWebhooks(owner string) []*Webhook {
|
func GetWebhooks(owner string, organization string) []*Webhook {
|
||||||
webhooks := []*Webhook{}
|
webhooks := []*Webhook{}
|
||||||
err := adapter.Engine.Desc("created_time").Find(&webhooks, &Webhook{Owner: owner})
|
err := adapter.Engine.Desc("created_time").Find(&webhooks, &Webhook{Owner: owner, Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -62,10 +62,10 @@ func GetWebhooks(owner string) []*Webhook {
|
|||||||
return webhooks
|
return webhooks
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationWebhooks(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Webhook {
|
func GetPaginationWebhooks(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) []*Webhook {
|
||||||
webhooks := []*Webhook{}
|
webhooks := []*Webhook{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&webhooks)
|
err := session.Find(&webhooks, &Webhook{Organization: organization})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -94,3 +94,11 @@ func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pp *AlipayPaymentProvider) GetResponseError(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return "success"
|
||||||
|
} else {
|
||||||
|
return "fail"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
8
pp/gc.go
8
pp/gc.go
@@ -329,3 +329,11 @@ func (pp *GcPaymentProvider) GetInvoice(paymentName string, personName string, p
|
|||||||
|
|
||||||
return invoiceRespInfo.Url, nil
|
return invoiceRespInfo.Url, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pp *GcPaymentProvider) GetResponseError(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return "success"
|
||||||
|
} else {
|
||||||
|
return "fail"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user