Compare commits

...

60 Commits

Author SHA1 Message Date
4d860525bf feat: fix MFA page bug in OAuth login (#1889) 2023-05-24 21:31:03 +08:00
a64263f812 Support "#" in redirectUri 2023-05-24 21:29:45 +08:00
95ab2472ce Make logo length to 200 2023-05-23 21:57:35 +08:00
54e4747dbc refactor: code-optimization (#1885)
* refactor: code-optimization

* fix: restoring code style

* fix: gofmt
2023-05-23 17:54:51 +08:00
2389d47c34 Fix getFormattedDate() 2023-05-23 15:09:53 +08:00
9c4f0f042e fix: update Go dependencies (#1880)
* Vulnerability fix : CVE-2021-30080  CVE-2021-39391 CVE-2022-41723 CVE-2022-21698  CVE-2023-26483 etc.

* fix: CVE-2021-30080  CVE-2021-39391 CVE-2022-41723 CVE-2022-21698  CVE-2023-26483 etc.
2023-05-23 14:43:18 +08:00
e25e210b06 Improve upload resource page 2023-05-23 10:07:59 +08:00
df61a536c1 feat: add gzip support for static filter (#1875)
* feat: add gzip support for static filter

* Update static_filter.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-22 22:40:46 +08:00
47da3cdaa0 fix: resolve get resource list problem (#1877) 2023-05-22 22:35:12 +08:00
8d246f2d98 ci: revert "feat: fix UI in IE11" (#1879)
This reverts commit 44cd55e55f.
2023-05-22 22:21:56 +08:00
44cd55e55f feat: fix UI in IE11 (#1878) 2023-05-22 16:59:37 +08:00
6b42d35223 Fix state encoding for Moodle 2023-05-21 15:47:18 +08:00
c84150cede Fix getObject() bug for some API 2023-05-21 11:07:01 +08:00
de2689ac39 fix: revert "feat: fix UI in IE11" (#1873)
* Revert "feat: fix UI in IE11 (#1871)"

This reverts commit 319031da28.

* Update MfaVerifyForm.js
2023-05-21 00:43:42 +08:00
88c0856d17 feat: add subscription managment (#1858)
* feat: subscription managment

* fix: remove console log

* fix: webhooks

* fix linter

* fix: fix via gofumpt

* fix: review changes

* fix: Copyright 2023

* Update account.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-20 15:56:21 +08:00
319031da28 feat: fix UI in IE11 (#1871) 2023-05-19 21:47:02 +08:00
d20f3eb039 feat: support get user by userId and owner (#1870)
* feat: support get user by userId and owner

* Update user.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-19 21:46:44 +08:00
3e13e61d8f fix: sdk user is not Global Admin (#1868) 2023-05-19 21:24:55 +08:00
1260354b36 fix: add sAMAccountName for AD search (#1869) 2023-05-19 21:16:59 +08:00
af79fdedf2 feat: add new language: "pt" (#1837)
* feat: Added new locales pt-br

* fix: Changed pt-br to pt

* feat: Updated app.conf

* feat: Updated Setting.js

* feat: Changed folder locales pt-br to pt

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-19 16:57:44 +08:00
02333f2f0c Add "pt" language to backend 2023-05-19 16:42:31 +08:00
79bd58e0e6 Use util.GetId() 2023-05-19 14:26:32 +08:00
de73ff0e60 Add IsMaskedEnabled to provider API 2023-05-19 13:09:53 +08:00
a9d662f1bd Improve Migrator_1_314_0_PR_1841 speed 2023-05-19 02:55:36 +08:00
65dcbd2236 feat: compatible different uid of LDAP server (#1860)
* feat: compatible different uid of LDAP server

* Update organization.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-19 02:34:25 +08:00
6455734807 fix: fix incorrect LDAP sync status (#1859) 2023-05-18 22:03:53 +08:00
2eefeaffa7 feat: enforce by using resourceId (#1855)
* feat: enforce by using resourceId

* Update permission.go

* chore: fix cilint for enforcer.go

---------

Co-authored-by: tinhtt4 <tinhtt4@vng.com.vn>
Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-18 16:36:03 +08:00
04eaad1c80 Fix getCertByApplication() 2023-05-18 16:32:43 +08:00
9f084a0799 Can update user with OAuth values 2023-05-18 15:58:41 +08:00
293b9f1036 Remove languages in app.conf 2023-05-18 15:44:11 +08:00
437376c472 Fix CheckAccessPermission() 2023-05-18 13:36:16 +08:00
cc528c5d8c Add object to webhook 2023-05-17 23:57:14 +08:00
54e2055ffb Fix Beego filter: RecordMessage 2023-05-17 23:01:59 +08:00
983a30a2e0 Dingtalk now supports linking with corpMobile 2023-05-17 22:14:57 +08:00
37d0157d41 Fix application.EnableSignUp bug 2023-05-17 21:56:36 +08:00
d4dc236770 Fix refreshExpireInHours zero value issue 2023-05-17 20:47:59 +08:00
596742d782 Show org column better for admin (shared) 2023-05-17 17:30:47 +08:00
ce921c00cd fix: resolve the problem of cert being unable to be accessed properly (#1850)
* fix: resolve the problem of cert being unable to be accessed properly

* Update CertEditPage.js

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-17 17:17:58 +08:00
3830e443b0 Put webhook's RecordMessage() to FinishRouter stage 2023-05-17 16:32:12 +08:00
9092cad631 feat: support forced binding MFA after login (#1845) 2023-05-17 01:13:13 +08:00
0b5ecca5c8 Support empty application in page 2023-05-16 22:17:39 +08:00
3d9b305bbb Add /api/health API 2023-05-16 21:47:34 +08:00
0217e359e7 Update to Go 1.19.9 and Node 16.18.0 in Dockerfile 2023-05-16 20:33:31 +08:00
695a612e77 Improve passwordType in CheckPassword() 2023-05-16 20:14:05 +08:00
645d53e2c6 feat: User should have PasswordType like Organization (#1841)
* fixes #1840: [backend] User should have PasswordType like Organization is

* Update migrator.go

* Update and rename migrator_1_314_0_PR_1838.go to migrator_1_314_0_PR_1841.go

* Update user.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-05-16 20:11:19 +08:00
73b9d73f64 Add CustomFooter to Conf.js 2023-05-15 16:49:45 +08:00
c6675ee4e6 feat: AI responses support streaming (#1826)
Is an AI response that supports streaming return
2023-05-13 11:31:20 +08:00
6f0b7f3f24 Support modelId arg in Enforce() API 2023-05-12 21:39:57 +08:00
776a682fae Improve args of Enforce() API 2023-05-12 21:32:48 +08:00
96a3db21a1 Support LDAP search by user tag 2023-05-12 13:03:43 +08:00
c33d537ac1 Add formCssMobile to application 2023-05-12 12:16:03 +08:00
5214d48486 Fix authorized issue of UploadResource() API 2023-05-12 01:00:06 +08:00
e360b06d12 Fix termsOfUse upload in application edit page 2023-05-10 23:57:03 +08:00
3c871c38df Fix message and chat owner bug 2023-05-10 22:32:32 +08:00
7df043fb15 fix: fix cypress error (#1817)
* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error

* fix: fix cypress error
2023-05-09 20:51:07 +08:00
cb542ae46a feat: fix org admin permissions (#1822) 2023-05-09 00:06:52 +08:00
3699177837 fix: fix URL path in MinIO storage provider(#1818) 2023-05-08 16:48:56 +08:00
3a6846b32c feat: fix bug that logging in with account/password cannot redirect successfully (When Casdoor working as a OAuth server) (#1819) 2023-05-08 16:37:56 +08:00
50586a9716 feat: improve determination about whether dest is mail or phone and mask props (#1814) 2023-05-07 21:19:51 +08:00
9201992140 Fix LDAP server bugs 2023-05-06 23:31:46 +08:00
175 changed files with 7116 additions and 576 deletions

4
.gitignore vendored
View File

@ -29,4 +29,6 @@ lastupdate.tmp
commentsRouter*.go
# ignore build result
casdoor
casdoor
server_linux_arm64
server_linux_amd64

View File

@ -1,11 +1,11 @@
FROM node:16.13.0 AS FRONT
FROM node:16.18.0 AS FRONT
WORKDIR /web
COPY ./web .
RUN yarn config set registry https://registry.npmmirror.com
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
COPY . .
RUN ./build.sh

View File

@ -18,6 +18,7 @@ import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
@ -78,7 +79,10 @@ func QueryAnswerStream(authToken string, question string, writer io.Writer, buil
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)
@ -122,11 +126,13 @@ func QueryAnswerStream(authToken string, question string, writer io.Writer, buil
}
}
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)
}

View File

@ -15,13 +15,13 @@
package authz
import (
"fmt"
"strings"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
stringadapter "github.com/qiangmzsx/string-adapter/v2"
)
@ -88,6 +88,7 @@ p, *, *, GET, /api/logout, *, *
p, *, *, GET, /api/get-account, *, *
p, *, *, GET, /api/userinfo, *, *
p, *, *, GET, /api/user, *, *
p, *, *, GET, /api/health, *, *
p, *, *, POST, /api/webhook, *, *
p, *, *, GET, /api/get-webhook-event, *, *
p, *, *, GET, /api/get-captcha-status, *, *
@ -123,6 +124,9 @@ p, *, *, GET, /api/get-release, *, *
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, *, *
`
sa := stringadapter.NewAdapter(ruleText)
@ -149,9 +153,8 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
}
}
userId := fmt.Sprintf("%s/%s", subOwner, subName)
user := object.GetUser(userId)
if user != nil && user.IsAdmin && (subOwner == objOwner || (objOwner == "admin" && subOwner == objName)) {
user := object.GetUser(util.GetId(subOwner, subName))
if user != nil && user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
return true
}

View File

@ -20,5 +20,4 @@ staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false
batchSize = 100
ldapServerPort = 389
languages = en,zh,es,fr,de,id,ja,ko,ru,vi
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}

View File

@ -112,13 +112,8 @@ func GetLanguage(language string) string {
if len(language) < 2 {
return "en"
}
language = language[0:2]
if strings.Contains(GetConfigString("languages"), language) {
return language
} else {
return "en"
return language[0:2]
}
}

View File

@ -84,7 +84,7 @@ func (c *ApiController) Signup() {
return
}
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", authForm.Organization))
organization := object.GetOrganization(util.GetId("admin", authForm.Organization))
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
@ -126,7 +126,7 @@ func (c *ApiController) Signup() {
username = id
}
initScore, err := getInitScore(organization)
initScore, err := organization.GetInitScore()
if err != nil {
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
return
@ -189,6 +189,11 @@ func (c *ApiController) Signup() {
object.DisableVerificationCode(authForm.Email)
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.Organization = application.Organization
record.User = user.Name

View File

@ -118,8 +118,7 @@ func (c *ApiController) GetOrganizationApplications() {
}
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.ServeJSON()
} else {

View File

@ -141,7 +141,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
c.setExpireForSession()
}
if resp.Status == "ok" && user.Owner == object.CasdoorOrganization && application.Name == object.CasdoorApplication {
if resp.Status == "ok" {
object.AddSession(&object.Session{
Owner: user.Owner,
Name: user.Name,
@ -312,6 +312,11 @@ func (c *ApiController) Login() {
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.Organization = application.Organization
record.User = user.Name
@ -330,7 +335,7 @@ func (c *ApiController) Login() {
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", authForm.Provider))
providerItem := application.GetProviderItem(provider.Name)
if !providerItem.IsProviderVisible() {
@ -391,7 +396,7 @@ func (c *ApiController) Login() {
if authForm.Method == "signup" {
user := &object.User{}
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" {
user = object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
}
@ -411,24 +416,31 @@ func (c *ApiController) Login() {
util.SafeGoroutine(func() { object.AddRecord(record) })
} else if provider.Category == "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 {
// find user that has the same email
user = object.GetUserByField(application.Organization, "email", userInfo.Email)
if 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 !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
tmpUser := object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Username))
tmpUser := object.GetUser(util.GetId(application.Organization, userInfo.Username))
if tmpUser != nil {
uid, err := uuid.NewRandom()
if err != nil {
@ -442,7 +454,7 @@ func (c *ApiController) Login() {
properties := map[string]string{}
properties["no"] = strconv.Itoa(object.GetUserCount(application.Organization, "", "") + 2)
initScore, err := getInitScore(organization)
initScore, err := organization.GetInitScore()
if err != nil {
c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
return

View File

@ -48,7 +48,7 @@ func (c *ApiController) IsGlobalAdmin() bool {
func (c *ApiController) IsAdmin() bool {
isGlobalAdmin, user := c.isGlobalAdmin()
if user == nil {
if !isGlobalAdmin && user == nil {
return false
}

View File

@ -31,13 +31,14 @@ func (c *ApiController) GetCasbinAdapters() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
if limit == "" || page == "" {
adapters := object.GetCasbinAdapters(owner)
adapters := object.GetCasbinAdapters(owner, organization)
c.ResponseOk(adapters)
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, field, value)))
adapters := object.GetPaginationCasbinAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCasbinAdapterCount(owner, organization, field, value)))
adapters := object.GetPaginationCasbinAdapters(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(adapters, paginator.Nums())
}
}

View File

@ -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
// @Title GetCert
// @Tag Cert API

View File

@ -30,7 +30,7 @@ import (
// @Success 200 {array} object.Chat The Response object
// @router /get-chats [get]
func (c *ApiController) GetChats() {
owner := c.Input().Get("owner")
owner := "admin"
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")

View File

@ -18,30 +18,69 @@ import (
"encoding/json"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
func (c *ApiController) Enforce() {
var permissionRule object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
permissionId := c.Input().Get("permissionId")
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 {
c.ResponseError(err.Error())
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()
}
func (c *ApiController) BatchEnforce() {
var permissionRules []object.PermissionRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId")
var requests []object.CasbinRequest
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.BatchEnforce(permissionRules)
c.ServeJSON()
if permissionId != "" {
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() {

View File

@ -23,7 +23,8 @@ import (
type LdapResp struct {
// Groups []LdapRespGroup `json:"groups"`
Users []object.LdapRespUser `json:"users"`
Users []object.LdapUser `json:"users"`
ExistUuids []string `json:"existUuids"`
}
//type LdapRespGroup struct {
@ -32,8 +33,8 @@ type LdapResp struct {
//}
type LdapSyncResp struct {
Exist []object.LdapRespUser `json:"exist"`
Failed []object.LdapRespUser `json:"failed"`
Exist []object.LdapUser `json:"exist"`
Failed []object.LdapUser `json:"failed"`
}
// GetLdapUsers
@ -71,27 +72,17 @@ func (c *ApiController) GetLdapUsers() {
return
}
var resp LdapResp
uuids := make([]string, len(users))
for _, user := range users {
resp.Users = append(resp.Users, object.LdapRespUser{
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)
for i, user := range users {
uuids[i] = user.GetLdapUuid()
}
existUuids := object.GetExistUuids(ldapServer.Owner, uuids)
c.ResponseOk(resp, existUuids)
resp := LdapResp{
Users: object.AutoAdjustLdapUser(users),
ExistUuids: existUuids,
}
c.ResponseOk(resp)
}
// GetLdaps
@ -206,7 +197,7 @@ func (c *ApiController) DeleteLdap() {
func (c *ApiController) SyncLdapUsers() {
owner := c.Input().Get("owner")
ldapId := c.Input().Get("ldapId")
var users []object.LdapRespUser
var users []object.LdapUser
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
if err != nil {
c.ResponseError(err.Error())
@ -215,10 +206,10 @@ func (c *ApiController) SyncLdapUsers() {
object.UpdateLdapSyncTime(ldapId)
exist, failed := object.SyncLdapUsers(owner, users, ldapId)
exist, failed, _ := object.SyncLdapUsers(owner, users, ldapId)
c.ResponseOk(&LdapSyncResp{
Exist: *exist,
Failed: *failed,
Exist: exist,
Failed: failed,
})
}

View File

@ -41,7 +41,7 @@ func (c *ApiController) GetMessages() {
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
chat := c.Input().Get("chat")
organization := c.Input().Get("organization")
if limit == "" || page == "" {
var messages []*object.Message
if chat == "" {
@ -54,8 +54,8 @@ func (c *ApiController) GetMessages() {
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetMessageCount(owner, field, value)))
messages := object.GetMaskedMessages(object.GetPaginationMessages(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetMessageCount(owner, organization, field, value)))
messages := object.GetMaskedMessages(object.GetPaginationMessages(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
c.ResponseOk(messages, paginator.Nums())
}
}
@ -107,9 +107,9 @@ func (c *ApiController) GetMessageAnswer() {
return
}
chatId := util.GetId(message.Owner, message.Chat)
chatId := util.GetId("admin", message.Chat)
chat := object.GetChat(chatId)
if chat == nil {
if chat == nil || chat.Organization != message.Organization {
c.ResponseErrorStream(fmt.Sprintf(c.T("chat:The chat: %s is not found"), chatId))
return
}
@ -144,12 +144,18 @@ func (c *ApiController) GetMessageAnswer() {
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 {
@ -158,9 +164,6 @@ func (c *ApiController) GetMessageAnswer() {
answer := stringBuilder.String()
fmt.Printf("Question: [%s]\n", questionMessage.Text)
fmt.Printf("Answer: [%s]\n", answer)
message.Text = answer
object.UpdateMessage(message.GetId(), message)
}
@ -202,10 +205,18 @@ func (c *ApiController) AddMessage() {
return
}
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 {
chatId := util.GetId(message.Owner, message.Chat)
chat := object.GetChat(chatId)
if chat != nil && chat.Type == "AI" {
answerMessage := &object.Message{
Owner: message.Owner,

View File

@ -186,5 +186,9 @@ func (c *ApiController) SetPreferredMfa() {
}
object.UpdateUser(userId, user, []string{"multi_factor_auths"}, user.IsAdminUser())
c.ResponseOk(user.MultiFactorAuths)
for i, mfaProp := range mfaProps {
mfaProps[i] = object.GetMaskedProps(mfaProp)
}
c.ResponseOk(mfaProps)
}

137
controllers/plan.go Normal file
View 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
View 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()
}

View File

@ -37,13 +37,19 @@ func (c *ApiController) GetProviders() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
ok, isMaskEnabled := c.IsMaskedEnabled()
if !ok {
return
}
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedProviders(object.GetProviders(owner))
c.Data["json"] = object.GetMaskedProviders(object.GetProviders(owner), isMaskEnabled)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
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())
}
}
@ -61,13 +67,19 @@ func (c *ApiController) GetGlobalProviders() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
ok, isMaskEnabled := c.IsMaskedEnabled()
if !ok {
return
}
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedProviders(object.GetGlobalProviders())
c.Data["json"] = object.GetMaskedProviders(object.GetGlobalProviders(), isMaskEnabled)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
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())
}
}
@ -81,7 +93,13 @@ func (c *ApiController) GetGlobalProviders() {
// @router /get-provider [get]
func (c *ApiController) GetProvider() {
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()
}

View File

@ -21,6 +21,7 @@ import (
"io"
"mime"
"path/filepath"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
@ -235,10 +236,21 @@ func (c *ApiController) UploadResource() {
user.Avatar = fileUrl
object.UpdateUser(user.GetId(), user, []string{"avatar"}, false)
case "termsOfUse":
applicationId := fmt.Sprintf("admin/%s", parent)
app := object.GetApplication(applicationId)
app.TermsOfUse = fileUrl
object.UpdateApplication(applicationId, app)
user := object.GetUserNoCheck(util.GetId(owner, username))
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(owner, username)))
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)

125
controllers/subscription.go Normal file
View 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()
}

View File

@ -37,13 +37,14 @@ func (c *ApiController) GetSyncers() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
if limit == "" || page == "" {
c.Data["json"] = object.GetSyncers(owner)
c.Data["json"] = object.GetOrganizationSyncers(owner, organization)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner, field, value)))
syncers := object.GetPaginationSyncers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSyncerCount(owner, organization, field, value)))
syncers := object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(syncers, paginator.Nums())
}
}

View File

@ -59,3 +59,13 @@ func (c *ApiController) GetVersionInfo() {
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()
}

View File

@ -39,13 +39,14 @@ func (c *ApiController) GetTokens() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
if limit == "" || page == "" {
c.Data["json"] = object.GetTokens(owner)
c.Data["json"] = object.GetTokens(owner, organization)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner, field, value)))
tokens := object.GetPaginationTokens(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetTokenCount(owner, organization, field, value)))
tokens := object.GetPaginationTokens(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(tokens, paginator.Nums())
}
}

View File

@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
// @Title GetUser
// @Tag User API
// @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 email query string false "The email 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")
phone := c.Input().Get("phone")
userId := c.Input().Get("userId")
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 == "" {
owner = util.GetOwnerFromId(id)
}
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", owner))
organization := object.GetOrganization(util.GetId("admin", owner))
if !organization.IsProfilePublic {
requestUserId := c.GetSessionUsername()
hasPermission, err := object.CheckUserPermission(requestUserId, id, false, c.GetAcceptLanguage())
@ -115,7 +121,7 @@ func (c *ApiController) GetUser() {
case phone != "":
user = object.GetUserByPhone(owner, phone)
case userId != "":
user = object.GetUserByUserId(owner, userId)
user = userFromUserId
default:
user = object.GetUser(id)
}

View File

@ -16,7 +16,6 @@ package controllers
import (
"fmt"
"strconv"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n"
@ -115,12 +114,25 @@ func (c *ApiController) RequireAdmin() (string, bool) {
return user.Owner, true
}
func getInitScore(organization *object.Organization) (int, error) {
if organization != nil {
return organization.InitScore, nil
} else {
return strconv.Atoi(conf.GetConfigString("initScore"))
// IsMaskedEnabled ...
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
isMaskEnabled := true
withSecret := c.Input().Get("withSecret")
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) {

View File

@ -37,13 +37,14 @@ func (c *ApiController) GetWebhooks() {
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
if limit == "" || page == "" {
c.Data["json"] = object.GetWebhooks(owner)
c.Data["json"] = object.GetWebhooks(owner, organization)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner, field, value)))
webhooks := object.GetPaginationWebhooks(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetWebhookCount(owner, organization, field, value)))
webhooks := object.GetPaginationWebhooks(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
c.ResponseOk(webhooks, paginator.Nums())
}
}

View File

@ -54,4 +54,7 @@ type AuthForm struct {
MfaType string `json:"mfaType"`
Passcode string `json:"passcode"`
RecoveryCode string `json:"recoveryCode"`
Plan string `json:"plan"`
Pricing string `json:"pricing"`
}

20
go.mod
View File

@ -8,8 +8,9 @@ require (
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 // indirect
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/casbin/casbin v1.9.1 // indirect
github.com/casbin/casbin/v2 v2.30.1
github.com/casdoor/go-sms-sender v0.6.1
github.com/casdoor/gomail/v2 v2.0.1
@ -18,6 +19,7 @@ require (
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
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/forestmgy/ldapserver v1.1.0
github.com/go-git/go-git/v5 v5.6.0
@ -28,24 +30,27 @@ require (
github.com/go-webauthn/webauthn v0.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
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/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/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/markbates/goth v1.75.2
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nyaruka/phonenumbers v1.1.5
github.com/pkoukk/tiktoken-go v0.1.1
github.com/prometheus/client_golang v1.7.0
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/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.6.0
github.com/russellhaering/goxmldsig v1.1.1
github.com/russellhaering/gosaml2 v0.9.0
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/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
@ -57,10 +62,11 @@ require (
github.com/xorm-io/xorm v1.1.6
github.com/yusufpapurcu/wmi v1.2.2 // indirect
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
gopkg.in/ini.v1 v1.67.0 // indirect
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
)

72
go.sum
View File

@ -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/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-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/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
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/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/beego/beego v1.12.11 h1:MWKcnpavb7iAIS0m6uuEq6pHKkYvGNw/5umIUKqL7jM=
github.com/beego/beego v1.12.11/go.mod h1:QURFL1HldOcCZAxnc1cZ7wrplsYR5dKPHFjmk6WkLAs=
github.com/beego/beego v1.12.12 h1:ARY1sNVSS23N0mEQIhSqRDTyyDlx95JY0V3GogBbZbQ=
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/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
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/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/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.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.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
@ -168,8 +170,9 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
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/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.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/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -205,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-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/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/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
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.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/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@ -273,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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
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.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-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
@ -292,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.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.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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
@ -321,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/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
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.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/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
@ -356,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/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.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -368,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/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.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/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
@ -377,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/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.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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -408,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.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
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.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/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -419,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/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
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.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
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/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@ -445,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/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-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
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/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
@ -486,8 +500,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
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 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.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-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -496,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.4.0/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.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-20190507164030-5867b95ac084/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.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/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=
@ -518,11 +536,10 @@ 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.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
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.6.0/go.mod h1:CtzxpPr4+bevsATaqR0rw3aqrNlX274b+3C6vFTLCk8=
github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o=
github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM=
github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
github.com/russellhaering/gosaml2 v0.9.0 h1:CNMnH42z/GirrKjdmNrSS6bAAs47F9bPdl4PfRmVOIk=
github.com/russellhaering/gosaml2 v0.9.0/go.mod h1:byViER/1YPUa0Puj9ROZblpoq2jsE7h/CJmitzX0geU=
github.com/russellhaering/goxmldsig v1.2.0 h1:Y6GTTc9Un5hCxSzVz4UIWQ/zuVwDvzJk80guqzwx6Vg=
github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
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/sashabaranov/go-openai v1.9.1 h1:3N52HkJKo9Zlo/oe1AVv5ZkCOny0ra58/ACvAxkN3MM=
@ -531,8 +548,9 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
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/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-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/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
@ -548,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/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.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
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/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
@ -700,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-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-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-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-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@ -758,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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
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.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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -817,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-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-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-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -827,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-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-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-20210629170331-7dc0b73dc9fb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1005,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.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.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.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/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=
@ -1039,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.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.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
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-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -32,6 +32,7 @@ func TestGenerateI18nFrontend(t *testing.T) {
applyToOtherLanguage("frontend", "ko", data)
applyToOtherLanguage("frontend", "ru", data)
applyToOtherLanguage("frontend", "vi", data)
applyToOtherLanguage("frontend", "pt", data)
}
func TestGenerateI18nBackend(t *testing.T) {
@ -47,4 +48,5 @@ func TestGenerateI18nBackend(t *testing.T) {
applyToOtherLanguage("backend", "ko", data)
applyToOtherLanguage("backend", "ru", data)
applyToOtherLanguage("backend", "vi", data)
applyToOtherLanguage("backend", "pt", data)
}

View File

@ -73,23 +73,27 @@ func applyData(data1 *I18nData, data2 *I18nData) {
}
}
func Translate(lang string, error string) string {
tokens := strings.SplitN(error, ":", 2)
if !strings.Contains(error, ":") || len(tokens) != 2 {
return "Translate Error: " + error
func Translate(language string, errorText string) string {
tokens := strings.SplitN(errorText, ":", 2)
if !strings.Contains(errorText, ":") || len(tokens) != 2 {
return fmt.Sprintf("Translate error: the error text doesn't contain \":\", errorText = %s", errorText)
}
if langMap[lang] == nil {
file, _ := f.ReadFile("locales/" + lang + "/data.json")
if langMap[language] == nil {
file, err := f.ReadFile(fmt.Sprintf("locales/%s/data.json", language))
if err != nil {
return fmt.Sprintf("Translate error: the language \"%s\" is not supported, err = %s", language, err.Error())
}
data := I18nData{}
err := util.JsonToStruct(string(file), &data)
err = util.JsonToStruct(string(file), &data)
if err != nil {
panic(err)
}
langMap[lang] = data
langMap[language] = data
}
res := langMap[lang][tokens[0]][tokens[1]]
res := langMap[language][tokens[0]][tokens[1]]
if res == "" {
res = tokens[1]
}

View File

@ -179,8 +179,12 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
return nil, err
}
corpEmail, jobNumber, err := idp.getUserCorpEmail(userId, corpAccessToken)
corpMobile, corpEmail, jobNumber, err := idp.getUserCorpEmail(userId, corpAccessToken)
if err == nil {
if corpMobile != "" {
userInfo.Phone = corpMobile
}
if corpEmail != "" {
userInfo.Email = corpEmail
}
@ -264,27 +268,29 @@ func (idp *DingTalkIdProvider) getUserId(unionId string, accessToken string) (st
return data.Result.UserId, nil
}
func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (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["userid"] = userId
respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken)
if err != nil {
return "", "", err
return "", "", "", err
}
var data struct {
ErrMessage string `json:"errmsg"`
Result struct {
Mobile string `json:"mobile"`
Email string `json:"email"`
JobNumber string `json:"job_number"`
} `json:"result"`
}
err = json.Unmarshal(respBytes, &data)
if err != nil {
return "", "", err
return "", "", "", err
}
if data.ErrMessage != "ok" {
return "", "", fmt.Errorf(data.ErrMessage)
return "", "", "", fmt.Errorf(data.ErrMessage)
}
return data.Result.Email, data.Result.JobNumber, nil
return data.Result.Mobile, data.Result.Email, data.Result.JobNumber, nil
}

View File

@ -75,7 +75,9 @@ func (idp *WeComIdProvider) GetToken(code string) (*oauth2.Token, error) {
ProviderSecret string `json:"provider_secret"`
}{idp.Config.ClientID, idp.Config.ClientSecret}
data, err := idp.postWithBody(pTokenParams, "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token")
if err != nil {
return nil, err
}
pToken := &WeComProviderToken{}
err = json.Unmarshal(data, pToken)
if err != nil {

View File

@ -53,7 +53,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
}
bindPassword := string(r.AuthenticationSimple())
bindUser, err := object.CheckUserPassword(object.CasdoorOrganization, bindUsername, bindPassword, "en")
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
if err != "" {
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
res.SetResultCode(ldap.LDAPResultInvalidCredentials)
@ -113,6 +113,9 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
for _, attr := range r.Attributes() {
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
if string(attr) == "cn" {
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
}
}
w.Write(e)

View File

@ -57,16 +57,32 @@ func getNameAndOrgFromFilter(baseDN, filter string) (string, string, int) {
func getUsername(filter string) string {
nameIndex := strings.Index(filter, "cn=")
if nameIndex == -1 {
return "*"
nameIndex = strings.Index(filter, "uid=")
if nameIndex == -1 {
return "*"
} else {
nameIndex += 4
}
} else {
nameIndex += 3
}
var name string
for i := nameIndex + 3; filter[i] != ')'; i++ {
for i := nameIndex; filter[i] != ')'; i++ {
name = name + string(filter[i])
}
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) {
r := m.GetSearchRequest()
@ -87,13 +103,32 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
return nil, ldap.LDAPResultInsufficientAccessRights
}
} 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 {
log.Printf("ErrMsg = %v", err.Error())
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
}
}
@ -123,10 +158,16 @@ func getAttribute(attributeName string, user *object.User) message.AttributeValu
return message.AttributeValue(user.Name)
case "uid":
return message.AttributeValue(user.Name)
case "displayname":
return message.AttributeValue(user.DisplayName)
case "email":
return message.AttributeValue(user.Email)
case "mail":
return message.AttributeValue(user.Email)
case "mobile":
return message.AttributeValue(user.Phone)
case "title":
return message.AttributeValue(user.Tag)
case "userPassword":
return message.AttributeValue(getUserPasswordWithType(user))
default:

View File

@ -27,7 +27,6 @@ import (
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/routers"
_ "github.com/casdoor/casdoor/routers"
"github.com/casdoor/casdoor/util"
)
@ -59,8 +58,8 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
beego.BConfig.WebConfig.Session.SessionOn = true
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"

View File

@ -240,6 +240,21 @@ func (a *Adapter) createTable() {
if err != nil {
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 {

View File

@ -38,7 +38,7 @@ type Application struct {
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
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"`
Description string `xorm:"varchar(100)" json:"description"`
Organization string `xorm:"varchar(100)" json:"organization"`
@ -72,6 +72,7 @@ type Application struct {
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
ThemeData *ThemeData `xorm:"json" json:"themeData"`
FormCss string `xorm:"text" json:"formCss"`
FormCssMobile string `xorm:"text" json:"formCssMobile"`
FormOffset int `json:"formOffset"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
@ -109,7 +110,7 @@ func GetApplications(owner string) []*Application {
func GetOrganizationApplications(owner string, organization string) []*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 {
panic(err)
}
@ -131,7 +132,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 {
applications := []*Application{}
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 {
panic(err)
}
@ -144,12 +145,12 @@ func getProviderMap(owner string) map[string]*Provider {
m := map[string]*Provider{}
for _, provider := range providers {
// 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)
UpdateProvider(provider.Owner+"/"+provider.Name, provider)
}
m[provider.Name] = GetMaskedProvider(provider)
m[provider.Name] = GetMaskedProvider(provider, true)
}
return m
}
@ -325,6 +326,12 @@ func UpdateApplication(id string, application *Application) bool {
}
func AddApplication(application *Application) bool {
if application.Owner == "" {
application.Owner = "admin"
}
if application.Organization == "" {
application.Organization = "built-in"
}
if application.ClientId == "" {
application.ClientId = util.GenerateClientId()
}

View File

@ -46,9 +46,9 @@ type CasbinAdapter struct {
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, "", "")
count, err := session.Count(&CasbinAdapter{})
count, err := session.Count(&CasbinAdapter{Organization: organization})
if err != nil {
panic(err)
}
@ -56,9 +56,9 @@ func GetCasbinAdapterCount(owner, field, value string) int {
return int(count)
}
func GetCasbinAdapters(owner string) []*CasbinAdapter {
func GetCasbinAdapters(owner string, organization string) []*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 {
panic(err)
}
@ -66,10 +66,10 @@ func GetCasbinAdapters(owner string) []*CasbinAdapter {
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)
adapters := []*CasbinAdapter{}
err := session.Find(&adapters)
err := session.Find(&adapters, &CasbinAdapter{Organization: organization})
if err != nil {
panic(err)
}

View File

@ -55,8 +55,8 @@ func GetMaskedCerts(certs []*Cert) []*Cert {
}
func GetCertCount(owner, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Cert{})
session := GetSession("", -1, -1, field, value, "", "")
count, err := session.Where("owner = ? or owner = ? ", "admin", owner).Count(&Cert{})
if err != nil {
panic(err)
}
@ -66,7 +66,7 @@ func GetCertCount(owner, field, value string) int {
func GetCerts(owner string) []*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 {
panic(err)
}
@ -76,7 +76,38 @@ func GetCerts(owner string) []*Cert {
func GetPaginationCerts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*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)
if err != nil {
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 {
owner, name := util.GetOwnerAndNameFromId(id)
return getCert(owner, name)
@ -158,7 +207,7 @@ func (p *Cert) GetId() string {
func getCertByApplication(application *Application) *Cert {
if application.Cert != "" {
return getCert("admin", application.Cert)
return getCertByName(application.Cert)
} else {
return GetDefaultCert()
}

View File

@ -175,7 +175,11 @@ func CheckPassword(user *User, password string, lang string, options ...bool) st
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 organization.MasterPassword != "" {
if credManager.IsPasswordCorrect(password, organization.MasterPassword, "", organization.PasswordSalt) {
@ -207,7 +211,7 @@ func checkLdapUserPassword(user *User, password string, lang string) string {
}
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)
if err != nil {
@ -244,7 +248,7 @@ func CheckUserPassword(organization string, username string, password string, la
enableCaptcha = options[0]
}
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))
}
@ -282,6 +286,10 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
if userId != "" {
targetUser := GetUser(userId)
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)
}
@ -313,6 +321,10 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
}
func CheckAccessPermission(userId string, application *Application) (bool, error) {
if userId == "built-in/admin" {
return true, nil
}
permissions := GetPermissions(application.Organization)
allowed := true
var err error

View File

@ -90,7 +90,7 @@ func initBuiltInOrganization() bool {
CountryCodes: []string{"US", "ES", "CN", "FR", "DE", "GB", "JP", "KR", "VN", "ID", "SG", "IN"},
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
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,
AccountItems: getBuiltInAccountItems(),
EnableSoftDeletion: false,

View File

@ -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))
continue
}
existed, failed := SyncLdapUsers(ldap.Owner, LdapUsersToLdapRespUsers(users), ldap.Id)
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)
existed, failed, err := SyncLdapUsers(ldap.Owner, AutoAdjustLdapUser(users), ldap.Id)
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 {
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)))
}
}
}

View File

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util"
goldap "github.com/go-ldap/ldap/v3"
"github.com/thanhpk/randstr"
@ -35,35 +34,26 @@ type LdapConn struct {
// Cn string
//}
type ldapUser struct {
UidNumber string
Uid string
Cn string
GidNumber string
type LdapUser struct {
UidNumber string `json:"uidNumber"`
Uid string `json:"uid"`
Cn string `json:"cn"`
GidNumber string `json:"gidNumber"`
// Gcn string
Uuid string
DisplayName string
Uuid string `json:"uuid"`
DisplayName string `json:"displayName"`
Mail string
Email string
Email string `json:"email"`
EmailAddress string
TelephoneNumber string
Mobile string
MobileTelephoneNumber string
RegisteredAddress string
PostalAddress string
}
type LdapRespUser struct {
UidNumber string `json:"uidNumber"`
Uid string `json:"uid"`
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"`
GroupId string `json:"groupId"`
Phone string `json:"phone"`
Address string `json:"address"`
}
func (ldap *Ldap) GetLdapConn() (c *LdapConn, err error) {
@ -136,7 +126,7 @@ func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
return isMicrosoft, err
}
func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]LdapUser, error) {
SearchAttributes := []string{
"uidNumber", "cn", "sn", "gidNumber", "entryUUID", "displayName", "mail", "email",
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
@ -159,9 +149,9 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
return nil, errors.New("no result")
}
var ldapUsers []ldapUser
var ldapUsers []LdapUser
for _, entry := range searchResult.Entries {
var user ldapUser
var user LdapUser
for _, attribute := range entry.Attributes {
switch attribute.Name {
case "uidNumber":
@ -241,35 +231,30 @@ func (l *LdapConn) GetLdapUsers(ldapServer *Ldap) ([]ldapUser, error) {
// return groupMap, nil
// }
func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser {
res := make([]LdapRespUser, 0)
for _, user := range users {
res = append(res, LdapRespUser{
UidNumber: user.UidNumber,
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
Uuid: user.Uuid,
DisplayName: user.DisplayName,
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
Phone: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
Address: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
})
func AutoAdjustLdapUser(users []LdapUser) []LdapUser {
res := make([]LdapUser, len(users))
for i, user := range users {
res[i] = LdapUser{
UidNumber: user.UidNumber,
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
Uuid: user.GetLdapUuid(),
DisplayName: user.DisplayName,
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
RegisteredAddress: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
}
}
return res
}
func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]LdapRespUser, *[]LdapRespUser) {
var existUsers []LdapRespUser
var failedUsers []LdapRespUser
func SyncLdapUsers(owner string, syncUsers []LdapUser, ldapId string) (existUsers []LdapUser, failedUsers []LdapUser, err error) {
var uuids []string
for _, user := range respUsers {
for _, user := range syncUsers {
uuids = append(uuids, user.Uuid)
}
existUuids := GetExistUuids(owner, uuids)
organization := getOrganization("admin", owner)
ldap := GetLdap(ldapId)
@ -289,67 +274,59 @@ func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]Ld
}
tag := strings.Join(ou, ".")
for _, respUser := range respUsers {
for _, syncUser := range syncUsers {
existUuids := GetExistUuids(owner, uuids)
found := false
if len(existUuids) > 0 {
for _, existUuid := range existUuids {
if respUser.Uuid == existUuid {
existUsers = append(existUsers, respUser)
if syncUser.Uuid == existUuid {
existUsers = append(existUsers, syncUser)
found = true
}
}
}
if !found {
score, _ := organization.GetInitScore()
newUser := &User{
Owner: owner,
Name: respUser.buildLdapUserName(),
Name: syncUser.buildLdapUserName(),
CreatedTime: util.GetCurrentTime(),
DisplayName: respUser.buildLdapDisplayName(),
DisplayName: syncUser.buildLdapDisplayName(),
Avatar: organization.DefaultAvatar,
Email: respUser.Email,
Phone: respUser.Phone,
Address: []string{respUser.Address},
Email: syncUser.Email,
Phone: syncUser.Phone,
Address: []string{syncUser.Address},
Affiliation: affiliation,
Tag: tag,
Score: beego.AppConfig.DefaultInt("initScore", 2000),
Ldap: respUser.Uuid,
Score: score,
Ldap: syncUser.Uuid,
}
affected := AddUser(newUser)
if !affected {
failedUsers = append(failedUsers, respUser)
failedUsers = append(failedUsers, syncUser)
continue
}
}
}
return &existUsers, &failedUsers
return existUsers, failedUsers, err
}
func GetExistUuids(owner string, uuids []string) []string {
var users []User
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 {
panic(err)
}
if len(users) > 0 {
for _, result := range users {
existUuidSet[result.Ldap] = struct{}{}
}
}
for uuid := range existUuidSet {
existUuids = append(existUuids, uuid)
}
return existUuids
}
func (ldapUser *LdapRespUser) buildLdapUserName() string {
func (ldapUser *LdapUser) buildLdapUserName() string {
user := User{}
uidWithNumber := fmt.Sprintf("%s_%s", ldapUser.Uid, ldapUser.UidNumber)
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 ldapUser.Uid
if ldapUser.Uid != "" {
return ldapUser.Uid
}
return ldapUser.Cn
}
func (ldapUser *LdapRespUser) buildLdapDisplayName() string {
func (ldapUser *LdapUser) buildLdapDisplayName() string {
if ldapUser.DisplayName != "" {
return ldapUser.DisplayName
}
@ -375,7 +356,18 @@ func (ldapUser *LdapRespUser) buildLdapDisplayName() string {
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 {
return fmt.Sprintf("(&%s(uid=%s))", ldap.Filter, user.Name)
}
@ -393,6 +385,8 @@ func (user *User) getFieldFromLdapAttribute(attribute string) string {
switch attribute {
case "uid":
return user.Name
case "sAMAccountName":
return user.Name
case "mail":
return user.Email
case "mobile":

View File

@ -48,9 +48,9 @@ func GetMaskedMessages(messages []*Message) []*Message {
return messages
}
func GetMessageCount(owner, field, value string) int {
func GetMessageCount(owner, organization, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Message{})
count, err := session.Count(&Message{Organization: organization})
if err != nil {
panic(err)
}
@ -78,10 +78,10 @@ func GetChatMessages(chat string) []*Message {
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{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&messages)
err := session.Find(&messages, &Message{Organization: organization})
if err != nil {
panic(err)
}

View File

@ -51,6 +51,7 @@ const (
const (
MfaSessionUserId = "MfaSessionUserId"
NextMfa = "NextMfa"
RequiredMfa = "RequiredMfa"
)
func GetMfaUtil(providerType string, config *MfaProps) MfaInterface {

View File

@ -37,7 +37,7 @@ type SmsMfa struct {
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 countryCode != "" {
if !util.IsEmailValid(dest) {
dest, _ = util.GetE164Number(dest, countryCode)
}

View File

@ -26,6 +26,7 @@ func DoMigration() {
&Migrator_1_101_0_PR_1083{},
&Migrator_1_235_0_PR_1530{},
&Migrator_1_240_0_PR_1539{},
&Migrator_1_314_0_PR_1841{},
// more migrators add here in chronological order...
}

View File

@ -25,10 +25,7 @@ type Migrator_1_235_0_PR_1530 struct{}
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("casbin_rule")
if exist {
return true
}
return false
return exist
}
func (*Migrator_1_235_0_PR_1530) DoMigration() *migrate.Migration {

View 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
}

View File

@ -55,13 +55,8 @@ func isIpAddress(host string) bool {
// Attempt to parse the host as an IP address (both IPv4 and IPv6)
ip := net.ParseIP(hostWithoutPort)
if ip != nil {
// The host is an IP address
return true
}
// The host is not an IP address
return false
// if host is not nil is an IP address else is not an IP address
return ip != nil
}
func getOriginFromHost(host string) (string, string) {

View File

@ -16,7 +16,9 @@ package object
import (
"fmt"
"strconv"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util"
@ -38,6 +40,11 @@ type ThemeData struct {
IsEnabled bool `xorm:"bool" json:"isEnabled"`
}
type MfaItem struct {
Name string `json:"name"`
Rule string `json:"rule"`
}
type Organization struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
@ -59,6 +66,7 @@ type Organization struct {
EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
MfaItems []*MfaItem `xorm:"varchar(300)" json:"mfaItems"`
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
}
@ -408,3 +416,20 @@ func organizationChangeTrigger(oldName string, newName string) error {
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"))
}
}

View File

@ -15,8 +15,6 @@
package object
import (
"fmt"
"github.com/casdoor/casdoor/util"
"github.com/xorm-io/core"
)
@ -65,30 +63,6 @@ func (p *Permission) GetId() string {
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 {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Permission{})
@ -261,6 +235,16 @@ func GetPermissionsByRole(roleId string) []*Permission {
return permissions
}
func GetPermissionsByResource(resourceId string) []*Permission {
permissions := []*Permission{}
err := adapter.Engine.Where("resources like ?", "%"+resourceId+"\"%").Find(&permissions)
if err != nil {
panic(err)
}
return permissions
}
func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Submitter: submitter})
@ -271,6 +255,16 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
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 {
containsAsterisk := false
group, _ := util.GetOwnerAndNameFromId(userId)

View File

@ -62,7 +62,11 @@ func getEnforcer(permission *Permission) *casbin.Enforcer {
panic(err)
}
enforcer.InitWithModelAndAdapter(m, nil)
err = enforcer.InitWithModelAndAdapter(m, nil)
if err != nil {
panic(err)
}
enforcer.SetAdapter(adapter)
policyFilter := xormadapter.Filter{
@ -216,28 +220,23 @@ func removePolicies(permission *Permission) {
}
}
func Enforce(permissionRule *PermissionRule) bool {
permission := GetPermission(permissionRule.Id)
type CasbinRequest = []interface{}
func Enforce(permissionId string, request *CasbinRequest) bool {
permission := GetPermission(permissionId)
enforcer := getEnforcer(permission)
request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
allow, err := enforcer.Enforce(request...)
allow, err := enforcer.Enforce(*request...)
if err != nil {
panic(err)
}
return allow
}
func BatchEnforce(permissionRules []PermissionRule) []bool {
var requests [][]interface{}
for _, permissionRule := range permissionRules {
request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
requests = append(requests, request)
}
permission := GetPermission(permissionRules[0].Id)
func BatchEnforce(permissionId string, requests *[]CasbinRequest) []bool {
permission := GetPermission(permissionId)
enforcer := getEnforcer(permission)
allow, err := enforcer.BatchEnforce(requests)
allow, err := enforcer.BatchEnforce(*requests)
if err != nil {
panic(err)
}

145
object/plan.go Normal file
View 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
View 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
}

View File

@ -70,7 +70,11 @@ type Provider struct {
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 {
return nil
}
@ -88,9 +92,13 @@ func GetMaskedProvider(provider *Provider) *Provider {
return provider
}
func GetMaskedProviders(providers []*Provider) []*Provider {
func GetMaskedProviders(providers []*Provider, isMaskEnabled bool) []*Provider {
if !isMaskEnabled {
return providers
}
for _, provider := range providers {
provider = GetMaskedProvider(provider)
provider = GetMaskedProvider(provider, isMaskEnabled)
}
return providers
}
@ -310,7 +318,7 @@ func GetCaptchaProviderByApplication(applicationId, isCurrentProvider, lang stri
continue
}
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

View File

@ -47,7 +47,8 @@ type Record struct {
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
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"`
}
@ -60,6 +61,11 @@ func NewRecord(ctx *context.Context) *Record {
requestUri = requestUri[0:1000]
}
object := ""
if ctx.Input.RequestBody != nil && len(ctx.Input.RequestBody) != 0 {
object = string(ctx.Input.RequestBody)
}
record := Record{
Name: util.GenerateId(),
CreatedTime: util.GetCurrentTime(),
@ -68,6 +74,7 @@ func NewRecord(ctx *context.Context) *Record {
Method: ctx.Request.Method,
RequestUri: requestUri,
Action: action,
Object: object,
IsTriggered: false,
}
return &record
@ -159,7 +166,7 @@ func SendWebhooks(record *Record) error {
if matched {
if webhook.IsUserExtended {
user := getUser(record.Organization, record.User)
user := GetMaskedUser(getUser(record.Organization, record.User))
record.ExtendedUser = user
}

154
object/subscription.go Normal file
View 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)
}

View File

@ -55,9 +55,9 @@ type Syncer struct {
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, "", "")
count, err := session.Count(&Syncer{})
count, err := session.Count(&Syncer{Organization: organization})
if err != nil {
panic(err)
}
@ -75,10 +75,20 @@ func GetSyncers(owner string) []*Syncer {
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{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&syncers)
err := session.Find(&syncers, &Syncer{Organization: organization})
if err != nil {
panic(err)
}

View File

@ -91,9 +91,9 @@ type IntrospectionResponse struct {
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, "", "")
count, err := session.Count(&Token{})
count, err := session.Count(&Token{Organization: organization})
if err != nil {
panic(err)
}
@ -101,9 +101,9 @@ func GetTokenCount(owner, field, value string) int {
return int(count)
}
func GetTokens(owner string) []*Token {
func GetTokens(owner string, organization string) []*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 {
panic(err)
}
@ -111,10 +111,10 @@ func GetTokens(owner string) []*Token {
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{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&tokens)
err := session.Find(&tokens, &Token{Organization: organization})
if err != nil {
panic(err)
}

View File

@ -224,13 +224,16 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
if application.RefreshExpireInHours == 0 {
refreshExpireTime = expireTime
}
user = refineUser(user)
_, originBackend := getOriginFromHost(host)
name := util.GenerateId()
jti := fmt.Sprintf("%s/%s", application.Owner, name)
jti := util.GetId(application.Owner, name)
claims := Claims{
User: user,

View File

@ -41,6 +41,7 @@ type User struct {
Type string `xorm:"varchar(100)" json:"type"`
Password string `xorm:"varchar(100)" json:"password"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
FirstName string `xorm:"varchar(100)" json:"firstName"`
LastName string `xorm:"varchar(100)" json:"lastName"`
@ -250,6 +251,16 @@ func GetUsers(owner string) []*User {
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 {
users := []*User{}
err := adapter.Engine.Desc(sorter).Limit(limit, 0).Find(&users, &User{Owner: owner})
@ -461,6 +472,13 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) bool {
"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",
"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 isAdmin {

View File

@ -35,5 +35,6 @@ func (user *User) UpdateUserPassword(organization *Organization) {
if credManager != nil {
hashedPassword := credManager.GetHashedPassword(user.Password, user.PasswordSalt, organization.PasswordSalt)
user.Password = hashedPassword
user.PasswordType = organization.PasswordType
}
}

View File

@ -77,13 +77,17 @@ func GetUserByFields(organization string, field string) *User {
}
func SetUserField(user *User, field string, value string) bool {
bean := make(map[string]interface{})
if field == "password" {
organization := GetOrganizationByUser(user)
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 {
panic(err)
}

View File

@ -33,10 +33,10 @@ type VerifyResult struct {
}
const (
VerificationSuccess int = 0
wrongCodeError = 1
noRecordError = 2
timeoutError = 3
VerificationSuccess = iota
wrongCodeError
noRecordError
timeoutError
)
const (

View File

@ -42,9 +42,9 @@ type Webhook struct {
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, "", "")
count, err := session.Count(&Webhook{})
count, err := session.Count(&Webhook{Organization: organization})
if err != nil {
panic(err)
}
@ -52,9 +52,9 @@ func GetWebhookCount(owner, field, value string) int {
return int(count)
}
func GetWebhooks(owner string) []*Webhook {
func GetWebhooks(owner string, organization string) []*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 {
panic(err)
}
@ -62,10 +62,10 @@ func GetWebhooks(owner string) []*Webhook {
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{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&webhooks)
err := session.Find(&webhooks, &Webhook{Organization: organization})
if err != nil {
panic(err)
}

View File

@ -125,7 +125,11 @@ func AuthzFilter(ctx *context.Context) {
subOwner, subName := getSubject(ctx)
method := ctx.Request.Method
urlPath := getUrlPath(ctx.Request.URL.Path)
objOwner, objName := getObject(ctx)
objOwner, objName := "", ""
if urlPath != "/api/get-app-login" {
objOwner, objName = getObject(ctx)
}
if strings.HasPrefix(urlPath, "/api/notify-payment") {
urlPath = "/api/notify-payment"

View File

@ -43,7 +43,7 @@ func AutoSigninFilter(ctx *context.Context) {
return
}
userId := fmt.Sprintf("%s/%s", token.Organization, token.User)
userId := util.GetId(token.Organization, token.User)
application, _ := object.GetApplicationByUserId(fmt.Sprintf("app/%s", token.Application))
setSessionUser(ctx, userId)
setSessionOidc(ctx, token.Scope, application.ClientId)

View File

@ -15,8 +15,6 @@
package routers
import (
"fmt"
"github.com/beego/beego/context"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@ -50,7 +48,7 @@ func getUserByClientIdSecret(ctx *context.Context) string {
return ""
}
return fmt.Sprintf("%s/%s", application.Organization, application.Name)
return util.GetId(application.Organization, application.Name)
}
func RecordMessage(ctx *context.Context) {

View File

@ -184,6 +184,7 @@ func initAPI() {
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
beego.Router("/api/get-globle-certs", &controllers.ApiController{}, "GET:GetGlobleCerts")
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
@ -202,6 +203,24 @@ func initAPI() {
beego.Router("/api/add-message", &controllers.ApiController{}, "POST:AddMessage")
beego.Router("/api/delete-message", &controllers.ApiController{}, "POST:DeleteMessage")
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
beego.Router("/api/get-plans", &controllers.ApiController{}, "GET:GetPlans")
beego.Router("/api/get-plan", &controllers.ApiController{}, "GET:GetPlan")
beego.Router("/api/update-plan", &controllers.ApiController{}, "POST:UpdatePlan")
beego.Router("/api/add-plan", &controllers.ApiController{}, "POST:AddPlan")
beego.Router("/api/delete-plan", &controllers.ApiController{}, "POST:DeletePlan")
beego.Router("/api/get-pricings", &controllers.ApiController{}, "GET:GetPricings")
beego.Router("/api/get-pricing", &controllers.ApiController{}, "GET:GetPricing")
beego.Router("/api/update-pricing", &controllers.ApiController{}, "POST:UpdatePricing")
beego.Router("/api/add-pricing", &controllers.ApiController{}, "POST:AddPricing")
beego.Router("/api/delete-pricing", &controllers.ApiController{}, "POST:DeletePricing")
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
beego.Router("/api/get-product", &controllers.ApiController{}, "GET:GetProduct")
beego.Router("/api/update-product", &controllers.ApiController{}, "POST:UpdateProduct")
@ -246,6 +265,7 @@ func initAPI() {
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
beego.Handler("/api/metrics", promhttp.Handler())

View File

@ -15,6 +15,8 @@
package routers
import (
"compress/gzip"
"io"
"net/http"
"os"
"strings"
@ -28,6 +30,7 @@ import (
var (
oldStaticBaseUrl = "https://cdn.casbin.org"
newStaticBaseUrl = conf.GetConfigString("staticBaseUrl")
enableGzip, _ = conf.GetConfigBool("enableGzip")
)
func StaticFilter(ctx *context.Context) {
@ -53,7 +56,7 @@ func StaticFilter(ctx *context.Context) {
path2 := strings.TrimLeft(path, "web/build/images/")
if util.FileExist(path2) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, path2)
makeGzipResponse(ctx.ResponseWriter, ctx.Request, path2)
return
}
@ -62,7 +65,7 @@ func StaticFilter(ctx *context.Context) {
}
if oldStaticBaseUrl == newStaticBaseUrl {
http.ServeFile(ctx.ResponseWriter, ctx.Request, path)
makeGzipResponse(ctx.ResponseWriter, ctx.Request, path)
} else {
serveFileWithReplace(ctx.ResponseWriter, ctx.Request, path, oldStaticBaseUrl, newStaticBaseUrl)
}
@ -89,3 +92,24 @@ func serveFileWithReplace(w http.ResponseWriter, r *http.Request, name string, o
panic(err)
}
}
type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w gzipResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func makeGzipResponse(w http.ResponseWriter, r *http.Request, path string) {
if !enableGzip || !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
http.ServeFile(w, r, path)
return
}
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
http.ServeFile(gzw, r, path)
}

View File

@ -29,7 +29,7 @@ func NewMinIOS3StorageProvider(clientId string, clientSecret string, region stri
Endpoint: endpoint,
S3Endpoint: endpoint,
ACL: awss3.BucketCannedACLPublicRead,
S3ForcePathStyle: true,
S3ForcePathStyle: false,
})
return sp

File diff suppressed because it is too large Load Diff

View File

@ -177,6 +177,42 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/add-plan:
post:
tags:
- Plan API
description: add plan
operationId: ApiController.AddPlan
parameters:
- in: body
name: body
description: The details of the plan
required: true
schema:
$ref: '#/definitions/object.Plan'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/add-pricing:
post:
tags:
- Pricing API
description: add pricing
operationId: ApiController.AddPricing
parameters:
- in: body
name: body
description: The details of the pricing
required: true
schema:
$ref: '#/definitions/object.Pricing'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/add-product:
post:
tags:
@ -278,6 +314,24 @@ paths:
type: array
items:
type: string
/api/add-subscription:
post:
tags:
- Subscription API
description: add subscription
operationId: ApiController.AddSubscription
parameters:
- in: body
name: body
description: The details of the subscription
required: true
schema:
$ref: '#/definitions/object.Subscription'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/add-syncer:
post:
tags:
@ -552,6 +606,17 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/delete-mfa/:
post:
tags:
- MFA API
description: ': Delete MFA'
operationId: ApiController.DeleteMfa
responses:
"200":
description: object
schema:
$ref: '#/definitions/Response'
/api/delete-model:
post:
tags:
@ -624,6 +689,42 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/delete-plan:
post:
tags:
- Plan API
description: delete plan
operationId: ApiController.DeletePlan
parameters:
- in: body
name: body
description: The details of the plan
required: true
schema:
$ref: '#/definitions/object.Plan'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/delete-pricing:
post:
tags:
- Pricing API
description: delete pricing
operationId: ApiController.DeletePricing
parameters:
- in: body
name: body
description: The details of the pricing
required: true
schema:
$ref: '#/definitions/object.Pricing'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/delete-product:
post:
tags:
@ -702,6 +803,24 @@ paths:
type: array
items:
type: string
/api/delete-subscription:
post:
tags:
- Subscription API
description: delete subscription
operationId: ApiController.DeleteSubscription
parameters:
- in: body
name: body
description: The details of the subscription
required: true
schema:
$ref: '#/definitions/object.Subscription'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/delete-syncer:
post:
tags:
@ -995,6 +1114,19 @@ paths:
type: array
items:
$ref: '#/definitions/object.User'
/api/get-globle-certs:
get:
tags:
- Cert API
description: get globle certs
operationId: ApiController.GetGlobleCerts
responses:
"200":
description: The Response object
schema:
type: array
items:
$ref: '#/definitions/object.Cert'
/api/get-ldap:
get:
tags:
@ -1027,6 +1159,23 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/object.Message'
/api/get-message-answer:
get:
tags:
- Message API
description: get message answer
operationId: ApiController.GetMessageAnswer
parameters:
- in: query
name: id
description: The id ( owner/name ) of the message
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.Message'
/api/get-messages:
get:
tags:
@ -1241,6 +1390,82 @@ paths:
type: array
items:
$ref: '#/definitions/object.Permission'
/api/get-plan:
get:
tags:
- Plan API
description: get plan
operationId: ApiController.GetPlan
parameters:
- in: query
name: id
description: The id ( owner/name ) of the plan
required: true
type: string
- in: query
name: includeOption
description: Should include plan's option
type: boolean
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.Plan'
/api/get-plans:
get:
tags:
- Plan API
description: get plans
operationId: ApiController.GetPlans
parameters:
- in: query
name: owner
description: The owner of plans
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
$ref: '#/definitions/object.Plan'
/api/get-pricing:
get:
tags:
- Pricing API
description: get pricing
operationId: ApiController.GetPricing
parameters:
- in: query
name: id
description: The id ( owner/name ) of the pricing
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.pricing'
/api/get-pricings:
get:
tags:
- Pricing API
description: get pricings
operationId: ApiController.GetPricings
parameters:
- in: query
name: owner
description: The owner of pricings
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
$ref: '#/definitions/object.Pricing'
/api/get-product:
get:
tags:
@ -1277,6 +1502,17 @@ paths:
type: array
items:
$ref: '#/definitions/object.Product'
/api/get-prometheus-info:
get:
tags:
- Prometheus API
description: get Prometheus Info
operationId: ApiController.GetPrometheusInfo
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.PrometheusInfo'
/api/get-provider:
get:
tags:
@ -1466,6 +1702,42 @@ paths:
type: array
items:
$ref: '#/definitions/object.User'
/api/get-subscription:
get:
tags:
- Subscription API
description: get subscription
operationId: ApiController.GetSubscription
parameters:
- in: query
name: id
description: The id ( owner/name ) of the subscription
required: true
type: string
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/object.subscription'
/api/get-subscriptions:
get:
tags:
- Subscription API
description: get subscriptions
operationId: ApiController.GetSubscriptions
parameters:
- in: query
name: owner
description: The owner of subscriptions
required: true
type: string
responses:
"200":
description: The Response object
schema:
type: array
items:
$ref: '#/definitions/object.Subscription'
/api/get-syncer:
get:
tags:
@ -1975,6 +2247,39 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/mfa/setup/enable:
post:
tags:
- MFA API
description: enable totp
operationId: ApiController.MfaSetupEnable
responses:
"200":
description: object
schema:
$ref: '#/definitions/Response'
/api/mfa/setup/initiate:
post:
tags:
- MFA API
description: setup MFA
operationId: ApiController.MfaSetupInitiate
responses:
"200":
description: Response object
schema:
$ref: '#/definitions/The'
/api/mfa/setup/verify:
post:
tags:
- MFA API
description: setup verify totp
operationId: ApiController.MfaSetupVerify
responses:
"200":
description: object
schema:
$ref: '#/definitions/Response'
/api/notify-payment:
post:
tags:
@ -2048,6 +2353,17 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/set-preferred-mfa:
post:
tags:
- MFA API
description: ': Set specific Mfa Preferred'
operationId: ApiController.SetPreferredMfa
responses:
"200":
description: object
schema:
$ref: '#/definitions/Response'
/api/signup:
post:
tags:
@ -2268,6 +2584,52 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/update-plan:
post:
tags:
- Plan API
description: update plan
operationId: ApiController.UpdatePlan
parameters:
- in: query
name: id
description: The id ( owner/name ) of the plan
required: true
type: string
- in: body
name: body
description: The details of the plan
required: true
schema:
$ref: '#/definitions/object.Plan'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/update-pricing:
post:
tags:
- Pricing API
description: update pricing
operationId: ApiController.UpdatePricing
parameters:
- in: query
name: id
description: The id ( owner/name ) of the pricing
required: true
type: string
- in: body
name: body
description: The details of the pricing
required: true
schema:
$ref: '#/definitions/object.Pricing'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/update-product:
post:
tags:
@ -2361,6 +2723,29 @@ paths:
type: array
items:
type: string
/api/update-subscription:
post:
tags:
- Subscription API
description: update subscription
operationId: ApiController.UpdateSubscription
parameters:
- in: query
name: id
description: The id ( owner/name ) of the subscription
required: true
type: string
- in: body
name: body
description: The details of the subscription
required: true
schema:
$ref: '#/definitions/object.Subscription'
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
/api/update-syncer:
post:
tags:
@ -2555,10 +2940,10 @@ paths:
schema:
$ref: '#/definitions/Response'
definitions:
1183.0xc000455050.false:
1183.0x1400042eb70.false:
title: "false"
type: object
1217.0xc000455080.false:
1217.0x1400042eba0.false:
title: "false"
type: object
LaravelResponse:
@ -2567,6 +2952,9 @@ definitions:
Response:
title: Response
type: object
The:
title: The
type: object
controllers.AuthForm:
title: AuthForm
type: object
@ -2591,9 +2979,9 @@ definitions:
type: object
properties:
data:
$ref: '#/definitions/1183.0xc000455050.false'
$ref: '#/definitions/1183.0x1400042eb70.false'
data2:
$ref: '#/definitions/1217.0xc000455080.false'
$ref: '#/definitions/1217.0x1400042eba0.false'
msg:
type: string
name:
@ -2799,6 +3187,17 @@ definitions:
type: array
items:
type: string
object.GaugeVecInfo:
title: GaugeVecInfo
type: object
properties:
method:
type: string
name:
type: string
throughput:
type: number
format: double
object.Header:
title: Header
type: object
@ -2807,6 +3206,19 @@ definitions:
type: string
value:
type: string
object.HistogramVecInfo:
title: HistogramVecInfo
type: object
properties:
count:
type: integer
format: int64
latency:
type: string
method:
type: string
name:
type: string
object.IntrospectionResponse:
title: IntrospectionResponse
type: object
@ -2868,8 +3280,30 @@ definitions:
type: string
owner:
type: string
replyTo:
type: string
text:
type: string
object.MfaProps:
title: MfaProps
type: object
properties:
countryCode:
type: string
id:
type: string
isPreferred:
type: boolean
recoveryCodes:
type: array
items:
type: string
secret:
type: string
type:
type: string
url:
type: string
object.Model:
title: Model
type: object
@ -3098,6 +3532,67 @@ definitions:
type: array
items:
type: string
object.Plan:
title: Plan
type: object
properties:
createdTime:
type: string
currency:
type: string
description:
type: string
displayName:
type: string
name:
type: string
owner:
type: string
pricePerMonth:
type: number
format: double
pricePerYear:
type: number
format: double
role:
type: string
options:
type: array
object.Pricing:
title: Pricing
type: object
properties:
application:
type: string
approveTime:
type: string
approver:
type: string
createdTime:
type: string
description:
type: string
displayName:
type: string
hasTrial:
type: boolean
isEnabled:
type: boolean
name:
type: string
owner:
type: string
plans:
type: array
items:
type: string
state:
type: string
submitter:
type: string
trialDuration:
type: integer
format: int64
object.Product:
title: Product
type: object
@ -3141,6 +3636,21 @@ definitions:
type: string
tag:
type: string
object.PrometheusInfo:
title: PrometheusInfo
type: object
properties:
apiLatency:
type: array
items:
$ref: '#/definitions/object.HistogramVecInfo'
apiThroughput:
type: array
items:
$ref: '#/definitions/object.GaugeVecInfo'
totalThroughput:
type: number
format: double
object.Provider:
title: Provider
type: object
@ -3313,6 +3823,43 @@ definitions:
type: string
visible:
type: boolean
object.Subscription:
title: Subscription
type: object
properties:
approveTime:
type: string
approver:
type: string
createdTime:
type: string
description:
type: string
displayName:
type: string
duration:
type: integer
format: int64
endDate:
type: string
format: datetime
isEnabled:
type: boolean
name:
type: string
owner:
type: string
plan:
type: string
startDate:
type: string
format: datetime
state:
type: string
submitter:
type: string
user:
type: string
object.Syncer:
title: Syncer
type: object
@ -3612,6 +4159,10 @@ definitions:
type: string
microsoftonline:
type: string
multiFactorAuths:
type: array
items:
$ref: '#/definitions/object.MfaProps'
name:
type: string
naver:
@ -3778,6 +4329,12 @@ definitions:
type: string
url:
type: string
object.pricing:
title: pricing
type: object
object.subscription:
title: subscription
type: object
protocol.CredentialAssertion:
title: CredentialAssertion
type: object

View File

@ -66,13 +66,13 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
for i, row := range e.Rows {
for j, item := range row {
if i%2 == 0 {
if isChar[j] == true {
if isChar[j] {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
}
} else {
if isChar[j] == true {
if isChar[j] {
if item == nil {
newColumnValue[j] = nil
} else {
@ -103,7 +103,7 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
db.engine.Exec("BEGIN")
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
if isChar[j] {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
@ -128,7 +128,7 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
db.engine.Exec("BEGIN")
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
if isChar[j] {
if item == nil {
newColumnValue[j] = nil
} else {

View File

@ -25,7 +25,7 @@ import (
var rePhone *regexp.Regexp
func init() {
rePhone, _ = regexp.Compile("(\\d{3})\\d*(\\d{4})")
rePhone, _ = regexp.Compile(`(\d{3})\d*(\d{4})`)
}
func IsEmailValid(email string) bool {

View File

@ -1,16 +1,14 @@
describe('Test adapter', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test adapter", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/adapters");
cy.url().should("eq", "http://localhost:7001/adapters");
cy.get(selector.add).click();
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/adapters/built-in/")
});
})

View File

@ -1,6 +1,5 @@
describe('Test aplication', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test aplication", () => {

View File

@ -1,6 +1,5 @@
describe('Test certs', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test certs", () => {

View File

@ -1,6 +1,5 @@
describe('Test models', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test org", () => {

View File

@ -1,6 +1,5 @@
describe('Test Orgnazition', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test org", () => {

View File

@ -1,16 +1,14 @@
describe('Test payments', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test payments", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/payments");
cy.url().should("eq", "http://localhost:7001/payments");
cy.get(selector.add).click();
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/payments/")
});
})

View File

@ -1,6 +1,5 @@
describe('Test permissions', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test permissions", () => {

View File

@ -1,16 +1,14 @@
describe('Test products', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn > span"
};
it("test products", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/products");
cy.url().should("eq", "http://localhost:7001/products");
cy.get(selector.add).click();
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/products/")
});
})

View File

@ -1,6 +1,5 @@
describe('Test providers', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test providers", () => {

View File

@ -1,6 +1,5 @@
describe('Test records', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test records", () => {

View File

@ -1,6 +1,5 @@
describe('Test resource', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test resource", () => {

View File

@ -1,6 +1,5 @@
describe('Test roles', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test role", () => {

View File

@ -1,6 +1,5 @@
describe('Test sessions', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test sessions", () => {

View File

@ -1,16 +1,14 @@
describe('Test syncers', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test syncers", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/syncers");
cy.url().should("eq", "http://localhost:7001/syncers");
cy.get(selector.add).click();
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/syncers/")
});
})

View File

@ -1,6 +1,5 @@
describe('Test sysinfo', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test sysinfo", () => {

View File

@ -1,16 +1,14 @@
describe('Test tokens', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test records", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/tokens");
cy.url().should("eq", "http://localhost:7001/tokens");
cy.get(selector.add).click();
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/tokens/")
});
})

View File

@ -1,6 +1,5 @@
describe('Test User', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test user", () => {

View File

@ -7,10 +7,10 @@ describe('Test webhooks', () => {
add: ".ant-table-title > div > .ant-btn"
};
it("test webhooks", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/webhooks");
cy.url().should("eq", "http://localhost:7001/webhooks");
cy.get(selector.add).click();
cy.url().should("include","http://localhost:7001/webhooks/")
cy.get(selector.add,{timeout:10000}).click();
cy.url().should("include","http://localhost:7001/webhooks/");
});
})

View File

@ -23,19 +23,15 @@
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
const selector = {
username: "#input",
password: "#normal_login_password",
loginButton: ".ant-btn",
};
Cypress.Commands.add('login', ()=>{
cy.request({
method: "POST",
url: "http://localhost:7001/api/login",
body: {
"application": "app-built-in",
"organization": "built-in",
"username": "admin",
"password": "123",
"autoSignin": true,
"type": "login",
},
}).then((Response) => {
expect(Response).property("body").property("status").to.equal("ok");
});
cy.visit("http://localhost:7001");
cy.get(selector.username).type("admin");
cy.get(selector.password).type("123");
cy.get(selector.loginButton).click();
cy.url().should("eq", "http://localhost:7001/");
})

View File

@ -47,7 +47,7 @@ class AdapterEditPage extends React.Component {
}
getAdapter() {
AdapterBackend.getAdapter(this.state.owner, this.state.adapterName)
AdapterBackend.getAdapter("admin", this.state.adapterName)
.then((res) => {
if (res.status === "ok") {
this.setState({
@ -60,7 +60,7 @@ class AdapterEditPage extends React.Component {
}
getOrganizations() {
OrganizationBackend.getOrganizations("admin")
OrganizationBackend.getOrganizations(this.state.organizationName)
.then((res) => {
this.setState({
organizations: (res.msg === undefined) ? res : [],
@ -109,7 +109,7 @@ class AdapterEditPage extends React.Component {
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
</Col>
<Col span={22} >
<Select virtual={false} style={{width: "100%"}} value={this.state.adapter.organization} onChange={(value => {
<Select virtual={false} style={{width: "100%"}} disabled={!Setting.isAdminUser(this.props.account)} value={this.state.adapter.organization} onChange={(value => {
this.getModels(value);
this.updateAdapterField("organization", value);
this.updateAdapterField("owner", value);

View File

@ -26,10 +26,10 @@ class AdapterListPage extends BaseListPage {
newAdapter() {
const randomName = Setting.getRandomName();
return {
owner: "built-in",
owner: "admin",
name: `adapter_${randomName}`,
createdTime: moment().format(),
organization: "built-in",
organization: this.props.account.owner,
type: "Database",
host: "localhost",
port: 3306,
@ -247,7 +247,7 @@ class AdapterListPage extends BaseListPage {
value = params.type;
}
this.setState({loading: true});
AdapterBackend.getAdapters("", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
AdapterBackend.getAdapters("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => {
if (res.status === "ok") {
this.setState({

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