chore: migrate idp service

This commit is contained in:
Steven 2024-04-13 10:50:25 +08:00
parent a77703260f
commit c373131b89
37 changed files with 1096 additions and 1336 deletions

View File

@ -12,21 +12,21 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/usememos/memos/plugin/idp" "github.com/usememos/memos/plugin/idp"
"github.com/usememos/memos/store" storepb "github.com/usememos/memos/proto/gen/store"
) )
// IdentityProvider represents an OAuth2 Identity Provider. // IdentityProvider represents an OAuth2 Identity Provider.
type IdentityProvider struct { type IdentityProvider struct {
config *store.IdentityProviderOAuth2Config config *storepb.OAuth2Config
} }
// NewIdentityProvider initializes a new OAuth2 Identity Provider with the given configuration. // NewIdentityProvider initializes a new OAuth2 Identity Provider with the given configuration.
func NewIdentityProvider(config *store.IdentityProviderOAuth2Config) (*IdentityProvider, error) { func NewIdentityProvider(config *storepb.OAuth2Config) (*IdentityProvider, error) {
for v, field := range map[string]string{ for v, field := range map[string]string{
config.ClientID: "clientId", config.ClientId: "clientId",
config.ClientSecret: "clientSecret", config.ClientSecret: "clientSecret",
config.TokenURL: "tokenUrl", config.TokenUrl: "tokenUrl",
config.UserInfoURL: "userInfoUrl", config.UserInfoUrl: "userInfoUrl",
config.FieldMapping.Identifier: "fieldMapping.identifier", config.FieldMapping.Identifier: "fieldMapping.identifier",
} { } {
if v == "" { if v == "" {
@ -42,13 +42,13 @@ func NewIdentityProvider(config *store.IdentityProviderOAuth2Config) (*IdentityP
// ExchangeToken returns the exchanged OAuth2 token using the given authorization code. // ExchangeToken returns the exchanged OAuth2 token using the given authorization code.
func (p *IdentityProvider) ExchangeToken(ctx context.Context, redirectURL, code string) (string, error) { func (p *IdentityProvider) ExchangeToken(ctx context.Context, redirectURL, code string) (string, error) {
conf := &oauth2.Config{ conf := &oauth2.Config{
ClientID: p.config.ClientID, ClientID: p.config.ClientId,
ClientSecret: p.config.ClientSecret, ClientSecret: p.config.ClientSecret,
RedirectURL: redirectURL, RedirectURL: redirectURL,
Scopes: p.config.Scopes, Scopes: p.config.Scopes,
Endpoint: oauth2.Endpoint{ Endpoint: oauth2.Endpoint{
AuthURL: p.config.AuthURL, AuthURL: p.config.AuthUrl,
TokenURL: p.config.TokenURL, TokenURL: p.config.TokenUrl,
AuthStyle: oauth2.AuthStyleInParams, AuthStyle: oauth2.AuthStyleInParams,
}, },
} }
@ -69,7 +69,7 @@ func (p *IdentityProvider) ExchangeToken(ctx context.Context, redirectURL, code
// UserInfo returns the parsed user information using the given OAuth2 token. // UserInfo returns the parsed user information using the given OAuth2 token.
func (p *IdentityProvider) UserInfo(token string) (*idp.IdentityProviderUserInfo, error) { func (p *IdentityProvider) UserInfo(token string) (*idp.IdentityProviderUserInfo, error) {
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest(http.MethodGet, p.config.UserInfoURL, nil) req, err := http.NewRequest(http.MethodGet, p.config.UserInfoUrl, nil)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to new http request") return nil, errors.Wrap(err, "failed to new http request")
} }

View File

@ -14,24 +14,24 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/usememos/memos/plugin/idp" "github.com/usememos/memos/plugin/idp"
"github.com/usememos/memos/store" storepb "github.com/usememos/memos/proto/gen/store"
) )
func TestNewIdentityProvider(t *testing.T) { func TestNewIdentityProvider(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
config *store.IdentityProviderOAuth2Config config *storepb.OAuth2Config
containsErr string containsErr string
}{ }{
{ {
name: "no tokenUrl", name: "no tokenUrl",
config: &store.IdentityProviderOAuth2Config{ config: &storepb.OAuth2Config{
ClientID: "test-client-id", ClientId: "test-client-id",
ClientSecret: "test-client-secret", ClientSecret: "test-client-secret",
AuthURL: "", AuthUrl: "",
TokenURL: "", TokenUrl: "",
UserInfoURL: "https://example.com/api/user", UserInfoUrl: "https://example.com/api/user",
FieldMapping: &store.FieldMapping{ FieldMapping: &storepb.FieldMapping{
Identifier: "login", Identifier: "login",
}, },
}, },
@ -39,13 +39,13 @@ func TestNewIdentityProvider(t *testing.T) {
}, },
{ {
name: "no userInfoUrl", name: "no userInfoUrl",
config: &store.IdentityProviderOAuth2Config{ config: &storepb.OAuth2Config{
ClientID: "test-client-id", ClientId: "test-client-id",
ClientSecret: "test-client-secret", ClientSecret: "test-client-secret",
AuthURL: "", AuthUrl: "",
TokenURL: "https://example.com/token", TokenUrl: "https://example.com/token",
UserInfoURL: "", UserInfoUrl: "",
FieldMapping: &store.FieldMapping{ FieldMapping: &storepb.FieldMapping{
Identifier: "login", Identifier: "login",
}, },
}, },
@ -53,13 +53,13 @@ func TestNewIdentityProvider(t *testing.T) {
}, },
{ {
name: "no field mapping identifier", name: "no field mapping identifier",
config: &store.IdentityProviderOAuth2Config{ config: &storepb.OAuth2Config{
ClientID: "test-client-id", ClientId: "test-client-id",
ClientSecret: "test-client-secret", ClientSecret: "test-client-secret",
AuthURL: "", AuthUrl: "",
TokenURL: "https://example.com/token", TokenUrl: "https://example.com/token",
UserInfoURL: "https://example.com/api/user", UserInfoUrl: "https://example.com/api/user",
FieldMapping: &store.FieldMapping{ FieldMapping: &storepb.FieldMapping{
Identifier: "", Identifier: "",
}, },
}, },
@ -113,7 +113,7 @@ func TestIdentityProvider(t *testing.T) {
ctx := context.Background() ctx := context.Background()
const ( const (
testClientID = "test-client-id" testClientId = "test-client-id"
testCode = "test-code" testCode = "test-code"
testAccessToken = "test-access-token" testAccessToken = "test-access-token"
testSubject = "123456789" testSubject = "123456789"
@ -132,12 +132,12 @@ func TestIdentityProvider(t *testing.T) {
s := newMockServer(t, testCode, testAccessToken, userInfo) s := newMockServer(t, testCode, testAccessToken, userInfo)
oauth2, err := NewIdentityProvider( oauth2, err := NewIdentityProvider(
&store.IdentityProviderOAuth2Config{ &storepb.OAuth2Config{
ClientID: testClientID, ClientId: testClientId,
ClientSecret: "test-client-secret", ClientSecret: "test-client-secret",
TokenURL: fmt.Sprintf("%s/oauth2/token", s.URL), TokenUrl: fmt.Sprintf("%s/oauth2/token", s.URL),
UserInfoURL: fmt.Sprintf("%s/oauth2/userinfo", s.URL), UserInfoUrl: fmt.Sprintf("%s/oauth2/userinfo", s.URL),
FieldMapping: &store.FieldMapping{ FieldMapping: &storepb.FieldMapping{
Identifier: "sub", Identifier: "sub",
DisplayName: "name", DisplayName: "name",
Email: "email", Email: "email",

View File

@ -54,7 +54,7 @@ message IdentityProvider {
message IdentityProviderConfig { message IdentityProviderConfig {
oneof config { oneof config {
OAuth2Config oauth2 = 1; OAuth2Config oauth2_config = 1;
} }
} }

View File

@ -53,7 +53,7 @@ message Storage {
} }
message StorageConfig { message StorageConfig {
oneof storage_config { oneof config {
S3Config s3_config = 1; S3Config s3_config = 1;
} }
} }

View File

@ -1160,7 +1160,7 @@ Used internally for obfuscating the page token.
| Field | Type | Label | Description | | Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- | | ----- | ---- | ----- | ----------- |
| oauth2 | [OAuth2Config](#memos-api-v2-OAuth2Config) | | | | oauth2_config | [OAuth2Config](#memos-api-v2-OAuth2Config) | | |

View File

@ -156,7 +156,7 @@ type IdentityProviderConfig struct {
// Types that are assignable to Config: // Types that are assignable to Config:
// //
// *IdentityProviderConfig_Oauth2 // *IdentityProviderConfig_Oauth2Config
Config isIdentityProviderConfig_Config `protobuf_oneof:"config"` Config isIdentityProviderConfig_Config `protobuf_oneof:"config"`
} }
@ -199,9 +199,9 @@ func (m *IdentityProviderConfig) GetConfig() isIdentityProviderConfig_Config {
return nil return nil
} }
func (x *IdentityProviderConfig) GetOauth2() *OAuth2Config { func (x *IdentityProviderConfig) GetOauth2Config() *OAuth2Config {
if x, ok := x.GetConfig().(*IdentityProviderConfig_Oauth2); ok { if x, ok := x.GetConfig().(*IdentityProviderConfig_Oauth2Config); ok {
return x.Oauth2 return x.Oauth2Config
} }
return nil return nil
} }
@ -210,11 +210,11 @@ type isIdentityProviderConfig_Config interface {
isIdentityProviderConfig_Config() isIdentityProviderConfig_Config()
} }
type IdentityProviderConfig_Oauth2 struct { type IdentityProviderConfig_Oauth2Config struct {
Oauth2 *OAuth2Config `protobuf:"bytes,1,opt,name=oauth2,proto3,oneof"` Oauth2Config *OAuth2Config `protobuf:"bytes,1,opt,name=oauth2_config,json=oauth2Config,proto3,oneof"`
} }
func (*IdentityProviderConfig_Oauth2) isIdentityProviderConfig_Config() {} func (*IdentityProviderConfig_Oauth2Config) isIdentityProviderConfig_Config() {}
type FieldMapping struct { type FieldMapping struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -872,159 +872,159 @@ var file_api_v2_idp_service_proto_rawDesc = []byte{
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x22, 0x28, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x28, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10,
0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, 0x10, 0x01, 0x22, 0x58, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x41, 0x55, 0x54, 0x48, 0x32, 0x10, 0x01, 0x22, 0x65,
0x0a, 0x16, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x0a, 0x16, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x06, 0x6f, 0x61, 0x75, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0d, 0x6f, 0x61, 0x75, 0x74,
0x68, 0x32, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x68, 0x32, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x1a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4f,
0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x42, 0x08, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0c, 0x6f,
0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x67, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x61, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x08, 0x0a, 0x06, 0x63,
0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x67, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61,
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79,
0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73,
0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x22, 0x85, 0x02, 0x0a, 0x0c, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x85,
0x69, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x0a, 0x0c, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20,
0x63, 0x72, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c, 0x12, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20,
0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09,
0x28, 0x09, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x0a, 0x0d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x73, 0x65,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x55, 0x72, 0x6c, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a,
0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73,
0x64, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d,
0x1a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x46, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d,
0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x66, 0x69, 0x65, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x46, 0x69, 0x65, 0x6c,
0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d,
0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64,
0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6e, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52,
0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6e, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64,
0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x1a, 0x47, 0x65, 0x74,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x6a, 0x0a, 0x1b, 0x47,
0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f,
0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x6c, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x76, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x76, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x64, 0x65, 0x72, 0x52, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f,
0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x6d, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x6a, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x49,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x22, 0xa9, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x69, 0x64, 0x65, 0x72, 0x22, 0x6c, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x64,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61,
0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,
0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b,
0x22, 0x6d, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22,
0x33, 0x0a, 0x1d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf8, 0x06, 0x0a, 0x17, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x63, 0x65, 0x12, 0x93, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x2e, 0x6d,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x65, 0x72, 0x22, 0x6d, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52,
0x12, 0x28, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x72, 0x22, 0xa9, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e,
0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x6d, 0x65, 0x6d, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64,
0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10,
0x61, 0x6d, 0x65, 0x3d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x96, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2c, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f,
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x73, 0x12, 0xe4, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18,
0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x6d, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73,
0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x6d, 0x0a,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x4b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x33, 0x0a, 0x1d,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x22, 0x20, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0xf8, 0x06, 0x0a, 0x17, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x93, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x76, 0x32, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x9d, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x28, 0x2e,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x31, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x24, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65,
0x3d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x96, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x12, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x1b, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0xe4,
0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6f, 0xda, 0x41, 0x1d, 0x69, 0x64, 0x65, 0x6e, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61,
0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2c, 0x75, 0x70, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e,
0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x3a, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6f, 0xda, 0x41, 0x1d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x65, 0x72, 0x32, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x69, 0x64, 0x65, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x6e, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x3a, 0x11, 0x69, 0x64,
0x61, 0x6d, 0x65, 0x3d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x32,
0x69, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xa6, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x6e, 0x61, 0x6d, 0x65,
0x64, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x3d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xa6, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
0x1a, 0x2c, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x12, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e,
0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x2a, 0x22, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c,
0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x69, 0x64, 0x65, 0x65, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x2a, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0xda, 0x41, 0x04,
0x7d, 0x42, 0xa7, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x2a, 0x22, 0x2f, 0x61, 0x70, 0x69,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x0f, 0x49, 0x64, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x2f, 0x2a, 0x7d, 0x42, 0xa7,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69,
0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x2e, 0x76, 0x32, 0x42, 0x0f, 0x49, 0x64, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f,
0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02,
0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c,
0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d,
0x74, 0x6f, 0x33, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a,
0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -1062,7 +1062,7 @@ var file_api_v2_idp_service_proto_goTypes = []interface{}{
var file_api_v2_idp_service_proto_depIdxs = []int32{ var file_api_v2_idp_service_proto_depIdxs = []int32{
0, // 0: memos.api.v2.IdentityProvider.type:type_name -> memos.api.v2.IdentityProvider.Type 0, // 0: memos.api.v2.IdentityProvider.type:type_name -> memos.api.v2.IdentityProvider.Type
2, // 1: memos.api.v2.IdentityProvider.config:type_name -> memos.api.v2.IdentityProviderConfig 2, // 1: memos.api.v2.IdentityProvider.config:type_name -> memos.api.v2.IdentityProviderConfig
4, // 2: memos.api.v2.IdentityProviderConfig.oauth2:type_name -> memos.api.v2.OAuth2Config 4, // 2: memos.api.v2.IdentityProviderConfig.oauth2_config:type_name -> memos.api.v2.OAuth2Config
3, // 3: memos.api.v2.OAuth2Config.field_mapping:type_name -> memos.api.v2.FieldMapping 3, // 3: memos.api.v2.OAuth2Config.field_mapping:type_name -> memos.api.v2.FieldMapping
1, // 4: memos.api.v2.ListIdentityProvidersResponse.identity_providers:type_name -> memos.api.v2.IdentityProvider 1, // 4: memos.api.v2.ListIdentityProvidersResponse.identity_providers:type_name -> memos.api.v2.IdentityProvider
1, // 5: memos.api.v2.GetIdentityProviderResponse.identity_provider:type_name -> memos.api.v2.IdentityProvider 1, // 5: memos.api.v2.GetIdentityProviderResponse.identity_provider:type_name -> memos.api.v2.IdentityProvider
@ -1264,7 +1264,7 @@ func file_api_v2_idp_service_proto_init() {
} }
} }
file_api_v2_idp_service_proto_msgTypes[1].OneofWrappers = []interface{}{ file_api_v2_idp_service_proto_msgTypes[1].OneofWrappers = []interface{}{
(*IdentityProviderConfig_Oauth2)(nil), (*IdentityProviderConfig_Oauth2Config)(nil),
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{

View File

@ -144,10 +144,10 @@ type StorageConfig struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Types that are assignable to StorageConfig: // Types that are assignable to Config:
// //
// *StorageConfig_S3Config // *StorageConfig_S3Config
StorageConfig isStorageConfig_StorageConfig `protobuf_oneof:"storage_config"` Config isStorageConfig_Config `protobuf_oneof:"config"`
} }
func (x *StorageConfig) Reset() { func (x *StorageConfig) Reset() {
@ -182,29 +182,29 @@ func (*StorageConfig) Descriptor() ([]byte, []int) {
return file_api_v2_storage_service_proto_rawDescGZIP(), []int{1} return file_api_v2_storage_service_proto_rawDescGZIP(), []int{1}
} }
func (m *StorageConfig) GetStorageConfig() isStorageConfig_StorageConfig { func (m *StorageConfig) GetConfig() isStorageConfig_Config {
if m != nil { if m != nil {
return m.StorageConfig return m.Config
} }
return nil return nil
} }
func (x *StorageConfig) GetS3Config() *S3Config { func (x *StorageConfig) GetS3Config() *S3Config {
if x, ok := x.GetStorageConfig().(*StorageConfig_S3Config); ok { if x, ok := x.GetConfig().(*StorageConfig_S3Config); ok {
return x.S3Config return x.S3Config
} }
return nil return nil
} }
type isStorageConfig_StorageConfig interface { type isStorageConfig_Config interface {
isStorageConfig_StorageConfig() isStorageConfig_Config()
} }
type StorageConfig_S3Config struct { type StorageConfig_S3Config struct {
S3Config *S3Config `protobuf:"bytes,1,opt,name=s3_config,json=s3Config,proto3,oneof"` S3Config *S3Config `protobuf:"bytes,1,opt,name=s3_config,json=s3Config,proto3,oneof"`
} }
func (*StorageConfig_S3Config) isStorageConfig_StorageConfig() {} func (*StorageConfig_S3Config) isStorageConfig_Config() {}
type S3Config struct { type S3Config struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -800,120 +800,120 @@ var file_api_v2_storage_service_proto_rawDesc = []byte{
0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x24, 0x0a, 0x04, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x24, 0x0a, 0x04,
0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x53, 0x33, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x53, 0x33,
0x10, 0x01, 0x22, 0x58, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x10, 0x01, 0x22, 0x50, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00,
0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x10, 0x0a, 0x0e, 0x73, 0x74, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x08, 0x0a, 0x06, 0x63, 0x6f,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x82, 0x02, 0x0a, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x82, 0x02, 0x0a, 0x08, 0x53, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x08, 0x53, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01,
0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12,
0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
0x67, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63,
0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63,
0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b,
0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74,
0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x72, 0x6c, 0x5f, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x72, 0x6c, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x07,
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x6c, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12,
0x6c, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x1d, 0x0a, 0x0a, 0x75, 0x72, 0x6c, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x08, 0x20,
0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x6c, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x72, 0x6c, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x19,
0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x5f, 0x73, 0x69, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08,
0x67, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x53, 0x69, 0x67, 0x52, 0x07, 0x70, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x22, 0x47, 0x0a, 0x14, 0x43, 0x72, 0x65,
0x6e, 0x22, 0x47, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01,
0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x43, 0x72, 0x67, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72,
0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x73,
0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61,
0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x45, 0x0a, 0x12, 0x47, 0x65, 0x74,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x31, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
0x65, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f,
0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x73,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72,
0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x22, 0x23, 0x0a, 0x11,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x64, 0x22, 0x45, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x48, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73,
0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74,
0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
0x61, 0x67, 0x65, 0x22, 0x26, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x49, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52,
0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x05, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x14, 0x55,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x75, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x72, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d,
0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x61, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c,
0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x12, 0x73, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73,
0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6d, 0x6b, 0x22, 0x48, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61,
0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x74,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x65, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x22, 0x26, 0x0a, 0x14, 0x44,
0x22, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x69, 0x64, 0x7d, 0x12, 0x6f, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x02, 0x69, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f,
0x67, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x05, 0x0a,
0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52, 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71,
0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69,
0x61, 0x67, 0x65, 0x73, 0x12, 0x9e, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74,
0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x12, 0x73, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65,
0x44, 0xda, 0x41, 0x13, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70,
0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x3a, 0x07, 0x73, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x32, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3,
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74,
0x65, 0x2e, 0x69, 0x64, 0x7d, 0x12, 0x7c, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x6f, 0x0a, 0x0c, 0x4c,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x69, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x6d, 0x65,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53,
0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x73, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x22, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x2a, 0x15, 0x2f, 0x61, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69,
0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x12, 0x9e, 0x01, 0x0a,
0x69, 0x64, 0x7d, 0x42, 0xab, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x22,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x13, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70,
0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0xda, 0x41, 0x13, 0x73, 0x74, 0x6f, 0x72,
0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x67, 0x65, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82,
0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x3a, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x32, 0x1d,
0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73,
0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x7b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x69, 0x64, 0x7d, 0x12, 0x7c, 0x0a,
0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x22,
0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x17, 0x2a, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x42, 0xab, 0x01, 0x0a, 0x10,
0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
0x42, 0x13, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa,
0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02,
0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18,
0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73,
0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
} }
var ( var (

View File

@ -13,9 +13,12 @@
- [store/idp.proto](#store_idp-proto) - [store/idp.proto](#store_idp-proto)
- [FieldMapping](#memos-store-FieldMapping) - [FieldMapping](#memos-store-FieldMapping)
- [IdentityProvider](#memos-store-IdentityProvider)
- [IdentityProviderConfig](#memos-store-IdentityProviderConfig) - [IdentityProviderConfig](#memos-store-IdentityProviderConfig)
- [OAuth2Config](#memos-store-OAuth2Config) - [OAuth2Config](#memos-store-OAuth2Config)
- [IdentityProvider.Type](#memos-store-IdentityProvider-Type)
- [store/inbox.proto](#store_inbox-proto) - [store/inbox.proto](#store_inbox-proto)
- [InboxMessage](#memos-store-InboxMessage) - [InboxMessage](#memos-store-InboxMessage)
@ -175,6 +178,25 @@
<a name="memos-store-IdentityProvider"></a>
### IdentityProvider
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [int32](#int32) | | |
| name | [string](#string) | | |
| type | [IdentityProvider.Type](#memos-store-IdentityProvider-Type) | | |
| identifier_filter | [string](#string) | | |
| config | [IdentityProviderConfig](#memos-store-IdentityProviderConfig) | | |
<a name="memos-store-IdentityProviderConfig"></a> <a name="memos-store-IdentityProviderConfig"></a>
### IdentityProviderConfig ### IdentityProviderConfig
@ -183,7 +205,7 @@
| Field | Type | Label | Description | | Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- | | ----- | ---- | ----- | ----------- |
| oauth2 | [OAuth2Config](#memos-store-OAuth2Config) | | | | oauth2_config | [OAuth2Config](#memos-store-OAuth2Config) | | |
@ -212,6 +234,18 @@
<a name="memos-store-IdentityProvider-Type"></a>
### IdentityProvider.Type
| Name | Number | Description |
| ---- | ------ | ----------- |
| TYPE_UNSPECIFIED | 0 | |
| OAUTH2 | 1 | |

View File

@ -20,6 +20,131 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
type IdentityProvider_Type int32
const (
IdentityProvider_TYPE_UNSPECIFIED IdentityProvider_Type = 0
IdentityProvider_OAUTH2 IdentityProvider_Type = 1
)
// Enum value maps for IdentityProvider_Type.
var (
IdentityProvider_Type_name = map[int32]string{
0: "TYPE_UNSPECIFIED",
1: "OAUTH2",
}
IdentityProvider_Type_value = map[string]int32{
"TYPE_UNSPECIFIED": 0,
"OAUTH2": 1,
}
)
func (x IdentityProvider_Type) Enum() *IdentityProvider_Type {
p := new(IdentityProvider_Type)
*p = x
return p
}
func (x IdentityProvider_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (IdentityProvider_Type) Descriptor() protoreflect.EnumDescriptor {
return file_store_idp_proto_enumTypes[0].Descriptor()
}
func (IdentityProvider_Type) Type() protoreflect.EnumType {
return &file_store_idp_proto_enumTypes[0]
}
func (x IdentityProvider_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use IdentityProvider_Type.Descriptor instead.
func (IdentityProvider_Type) EnumDescriptor() ([]byte, []int) {
return file_store_idp_proto_rawDescGZIP(), []int{0, 0}
}
type IdentityProvider struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Type IdentityProvider_Type `protobuf:"varint,3,opt,name=type,proto3,enum=memos.store.IdentityProvider_Type" json:"type,omitempty"`
IdentifierFilter string `protobuf:"bytes,4,opt,name=identifier_filter,json=identifierFilter,proto3" json:"identifier_filter,omitempty"`
Config *IdentityProviderConfig `protobuf:"bytes,5,opt,name=config,proto3" json:"config,omitempty"`
}
func (x *IdentityProvider) Reset() {
*x = IdentityProvider{}
if protoimpl.UnsafeEnabled {
mi := &file_store_idp_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *IdentityProvider) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*IdentityProvider) ProtoMessage() {}
func (x *IdentityProvider) ProtoReflect() protoreflect.Message {
mi := &file_store_idp_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use IdentityProvider.ProtoReflect.Descriptor instead.
func (*IdentityProvider) Descriptor() ([]byte, []int) {
return file_store_idp_proto_rawDescGZIP(), []int{0}
}
func (x *IdentityProvider) GetId() int32 {
if x != nil {
return x.Id
}
return 0
}
func (x *IdentityProvider) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *IdentityProvider) GetType() IdentityProvider_Type {
if x != nil {
return x.Type
}
return IdentityProvider_TYPE_UNSPECIFIED
}
func (x *IdentityProvider) GetIdentifierFilter() string {
if x != nil {
return x.IdentifierFilter
}
return ""
}
func (x *IdentityProvider) GetConfig() *IdentityProviderConfig {
if x != nil {
return x.Config
}
return nil
}
type IdentityProviderConfig struct { type IdentityProviderConfig struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -27,14 +152,14 @@ type IdentityProviderConfig struct {
// Types that are assignable to Config: // Types that are assignable to Config:
// //
// *IdentityProviderConfig_Oauth2 // *IdentityProviderConfig_Oauth2Config
Config isIdentityProviderConfig_Config `protobuf_oneof:"config"` Config isIdentityProviderConfig_Config `protobuf_oneof:"config"`
} }
func (x *IdentityProviderConfig) Reset() { func (x *IdentityProviderConfig) Reset() {
*x = IdentityProviderConfig{} *x = IdentityProviderConfig{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_store_idp_proto_msgTypes[0] mi := &file_store_idp_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -47,7 +172,7 @@ func (x *IdentityProviderConfig) String() string {
func (*IdentityProviderConfig) ProtoMessage() {} func (*IdentityProviderConfig) ProtoMessage() {}
func (x *IdentityProviderConfig) ProtoReflect() protoreflect.Message { func (x *IdentityProviderConfig) ProtoReflect() protoreflect.Message {
mi := &file_store_idp_proto_msgTypes[0] mi := &file_store_idp_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -60,7 +185,7 @@ func (x *IdentityProviderConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use IdentityProviderConfig.ProtoReflect.Descriptor instead. // Deprecated: Use IdentityProviderConfig.ProtoReflect.Descriptor instead.
func (*IdentityProviderConfig) Descriptor() ([]byte, []int) { func (*IdentityProviderConfig) Descriptor() ([]byte, []int) {
return file_store_idp_proto_rawDescGZIP(), []int{0} return file_store_idp_proto_rawDescGZIP(), []int{1}
} }
func (m *IdentityProviderConfig) GetConfig() isIdentityProviderConfig_Config { func (m *IdentityProviderConfig) GetConfig() isIdentityProviderConfig_Config {
@ -70,9 +195,9 @@ func (m *IdentityProviderConfig) GetConfig() isIdentityProviderConfig_Config {
return nil return nil
} }
func (x *IdentityProviderConfig) GetOauth2() *OAuth2Config { func (x *IdentityProviderConfig) GetOauth2Config() *OAuth2Config {
if x, ok := x.GetConfig().(*IdentityProviderConfig_Oauth2); ok { if x, ok := x.GetConfig().(*IdentityProviderConfig_Oauth2Config); ok {
return x.Oauth2 return x.Oauth2Config
} }
return nil return nil
} }
@ -81,11 +206,11 @@ type isIdentityProviderConfig_Config interface {
isIdentityProviderConfig_Config() isIdentityProviderConfig_Config()
} }
type IdentityProviderConfig_Oauth2 struct { type IdentityProviderConfig_Oauth2Config struct {
Oauth2 *OAuth2Config `protobuf:"bytes,1,opt,name=oauth2,proto3,oneof"` Oauth2Config *OAuth2Config `protobuf:"bytes,1,opt,name=oauth2_config,json=oauth2Config,proto3,oneof"`
} }
func (*IdentityProviderConfig_Oauth2) isIdentityProviderConfig_Config() {} func (*IdentityProviderConfig_Oauth2Config) isIdentityProviderConfig_Config() {}
type FieldMapping struct { type FieldMapping struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -100,7 +225,7 @@ type FieldMapping struct {
func (x *FieldMapping) Reset() { func (x *FieldMapping) Reset() {
*x = FieldMapping{} *x = FieldMapping{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_store_idp_proto_msgTypes[1] mi := &file_store_idp_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -113,7 +238,7 @@ func (x *FieldMapping) String() string {
func (*FieldMapping) ProtoMessage() {} func (*FieldMapping) ProtoMessage() {}
func (x *FieldMapping) ProtoReflect() protoreflect.Message { func (x *FieldMapping) ProtoReflect() protoreflect.Message {
mi := &file_store_idp_proto_msgTypes[1] mi := &file_store_idp_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -126,7 +251,7 @@ func (x *FieldMapping) ProtoReflect() protoreflect.Message {
// Deprecated: Use FieldMapping.ProtoReflect.Descriptor instead. // Deprecated: Use FieldMapping.ProtoReflect.Descriptor instead.
func (*FieldMapping) Descriptor() ([]byte, []int) { func (*FieldMapping) Descriptor() ([]byte, []int) {
return file_store_idp_proto_rawDescGZIP(), []int{1} return file_store_idp_proto_rawDescGZIP(), []int{2}
} }
func (x *FieldMapping) GetIdentifier() string { func (x *FieldMapping) GetIdentifier() string {
@ -167,7 +292,7 @@ type OAuth2Config struct {
func (x *OAuth2Config) Reset() { func (x *OAuth2Config) Reset() {
*x = OAuth2Config{} *x = OAuth2Config{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_store_idp_proto_msgTypes[2] mi := &file_store_idp_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -180,7 +305,7 @@ func (x *OAuth2Config) String() string {
func (*OAuth2Config) ProtoMessage() {} func (*OAuth2Config) ProtoMessage() {}
func (x *OAuth2Config) ProtoReflect() protoreflect.Message { func (x *OAuth2Config) ProtoReflect() protoreflect.Message {
mi := &file_store_idp_proto_msgTypes[2] mi := &file_store_idp_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -193,7 +318,7 @@ func (x *OAuth2Config) ProtoReflect() protoreflect.Message {
// Deprecated: Use OAuth2Config.ProtoReflect.Descriptor instead. // Deprecated: Use OAuth2Config.ProtoReflect.Descriptor instead.
func (*OAuth2Config) Descriptor() ([]byte, []int) { func (*OAuth2Config) Descriptor() ([]byte, []int) {
return file_store_idp_proto_rawDescGZIP(), []int{2} return file_store_idp_proto_rawDescGZIP(), []int{3}
} }
func (x *OAuth2Config) GetClientId() string { func (x *OAuth2Config) GetClientId() string {
@ -249,46 +374,63 @@ var File_store_idp_proto protoreflect.FileDescriptor
var file_store_idp_proto_rawDesc = []byte{ var file_store_idp_proto_rawDesc = []byte{
0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x69, 0x64, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x69, 0x64, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x57, 0x6f, 0x12, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x82,
0x0a, 0x16, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x02, 0x0a, 0x10, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x06, 0x6f, 0x61, 0x75, 0x74, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x68, 0x32, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x42, 0x08, 0x0a, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74,
0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x67, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76,
0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,
0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x2b, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x5f, 0x66, 0x69,
0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x64, 0x65, 0x6e,
0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x06,
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d,
0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74,
0x22, 0x84, 0x02, 0x0a, 0x0c, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x28, 0x0a, 0x04, 0x54, 0x79, 0x70,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x41, 0x55, 0x54, 0x48,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x32, 0x10, 0x01, 0x22, 0x64, 0x0a, 0x16, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50,
0x72, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x40, 0x0a,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0d, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01,
0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f,
0x09, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x72, 0x65, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48,
0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x00, 0x52, 0x0c, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x55, 0x72, 0x6c, 0x12, 0x08, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x67, 0x0a, 0x0c, 0x46, 0x69, 0x65,
0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65,
0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69,
0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73,
0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x46, 0x69, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x93, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x08, 0x49, 0x64, 0x70, 0x69, 0x6c, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x43, 0x6f, 0x6e,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64,
0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64,
0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65,
0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53,
0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x72,
0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x55, 0x72, 0x6c,
0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20,
0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x22, 0x0a,
0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x55, 0x72,
0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0d, 0x66, 0x69, 0x65,
0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x46,
0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x66, 0x69, 0x65,
0x6c, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x93, 0x01, 0x0a, 0x0f, 0x63, 0x6f,
0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x08, 0x49,
0x64, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d,
0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73,
0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73,
0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53,
0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0xea, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -303,20 +445,25 @@ func file_store_idp_proto_rawDescGZIP() []byte {
return file_store_idp_proto_rawDescData return file_store_idp_proto_rawDescData
} }
var file_store_idp_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_store_idp_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_store_idp_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_store_idp_proto_goTypes = []interface{}{ var file_store_idp_proto_goTypes = []interface{}{
(*IdentityProviderConfig)(nil), // 0: memos.store.IdentityProviderConfig (IdentityProvider_Type)(0), // 0: memos.store.IdentityProvider.Type
(*FieldMapping)(nil), // 1: memos.store.FieldMapping (*IdentityProvider)(nil), // 1: memos.store.IdentityProvider
(*OAuth2Config)(nil), // 2: memos.store.OAuth2Config (*IdentityProviderConfig)(nil), // 2: memos.store.IdentityProviderConfig
(*FieldMapping)(nil), // 3: memos.store.FieldMapping
(*OAuth2Config)(nil), // 4: memos.store.OAuth2Config
} }
var file_store_idp_proto_depIdxs = []int32{ var file_store_idp_proto_depIdxs = []int32{
2, // 0: memos.store.IdentityProviderConfig.oauth2:type_name -> memos.store.OAuth2Config 0, // 0: memos.store.IdentityProvider.type:type_name -> memos.store.IdentityProvider.Type
1, // 1: memos.store.OAuth2Config.field_mapping:type_name -> memos.store.FieldMapping 2, // 1: memos.store.IdentityProvider.config:type_name -> memos.store.IdentityProviderConfig
2, // [2:2] is the sub-list for method output_type 4, // 2: memos.store.IdentityProviderConfig.oauth2_config:type_name -> memos.store.OAuth2Config
2, // [2:2] is the sub-list for method input_type 3, // 3: memos.store.OAuth2Config.field_mapping:type_name -> memos.store.FieldMapping
2, // [2:2] is the sub-list for extension type_name 4, // [4:4] is the sub-list for method output_type
2, // [2:2] is the sub-list for extension extendee 4, // [4:4] is the sub-list for method input_type
0, // [0:2] is the sub-list for field type_name 4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
} }
func init() { file_store_idp_proto_init() } func init() { file_store_idp_proto_init() }
@ -326,7 +473,7 @@ func file_store_idp_proto_init() {
} }
if !protoimpl.UnsafeEnabled { if !protoimpl.UnsafeEnabled {
file_store_idp_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { file_store_idp_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*IdentityProviderConfig); i { switch v := v.(*IdentityProvider); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -338,7 +485,7 @@ func file_store_idp_proto_init() {
} }
} }
file_store_idp_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { file_store_idp_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FieldMapping); i { switch v := v.(*IdentityProviderConfig); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -350,6 +497,18 @@ func file_store_idp_proto_init() {
} }
} }
file_store_idp_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { file_store_idp_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FieldMapping); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_store_idp_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*OAuth2Config); i { switch v := v.(*OAuth2Config); i {
case 0: case 0:
return &v.state return &v.state
@ -362,21 +521,22 @@ func file_store_idp_proto_init() {
} }
} }
} }
file_store_idp_proto_msgTypes[0].OneofWrappers = []interface{}{ file_store_idp_proto_msgTypes[1].OneofWrappers = []interface{}{
(*IdentityProviderConfig_Oauth2)(nil), (*IdentityProviderConfig_Oauth2Config)(nil),
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_store_idp_proto_rawDesc, RawDescriptor: file_store_idp_proto_rawDesc,
NumEnums: 0, NumEnums: 1,
NumMessages: 3, NumMessages: 4,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
GoTypes: file_store_idp_proto_goTypes, GoTypes: file_store_idp_proto_goTypes,
DependencyIndexes: file_store_idp_proto_depIdxs, DependencyIndexes: file_store_idp_proto_depIdxs,
EnumInfos: file_store_idp_proto_enumTypes,
MessageInfos: file_store_idp_proto_msgTypes, MessageInfos: file_store_idp_proto_msgTypes,
}.Build() }.Build()
File_store_idp_proto = out.File File_store_idp_proto = out.File

View File

@ -4,9 +4,22 @@ package memos.store;
option go_package = "gen/store"; option go_package = "gen/store";
message IdentityProvider {
int32 id = 1;
string name = 2;
enum Type {
TYPE_UNSPECIFIED = 0;
OAUTH2 = 1;
}
Type type = 3;
string identifier_filter = 4;
IdentityProviderConfig config = 5;
}
message IdentityProviderConfig { message IdentityProviderConfig {
oneof config { oneof config {
OAuth2Config oauth2 = 1; OAuth2Config oauth2_config = 1;
} }
} }

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"regexp"
"strings" "strings"
"time" "time"
@ -14,8 +13,6 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"github.com/usememos/memos/internal/util" "github.com/usememos/memos/internal/util"
"github.com/usememos/memos/plugin/idp"
"github.com/usememos/memos/plugin/idp/oauth2"
storepb "github.com/usememos/memos/proto/gen/store" storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/server/route/api/auth" "github.com/usememos/memos/server/route/api/auth"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
@ -40,7 +37,6 @@ type SignUp struct {
func (s *APIV1Service) registerAuthRoutes(g *echo.Group) { func (s *APIV1Service) registerAuthRoutes(g *echo.Group) {
g.POST("/auth/signin", s.SignIn) g.POST("/auth/signin", s.SignIn)
g.POST("/auth/signin/sso", s.SignInSSO)
g.POST("/auth/signout", s.SignOut) g.POST("/auth/signout", s.SignOut)
g.POST("/auth/signup", s.SignUp) g.POST("/auth/signup", s.SignUp)
} }
@ -111,117 +107,6 @@ func (s *APIV1Service) SignIn(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// SignInSSO godoc
//
// @Summary Sign-in to memos using SSO.
// @Tags auth
// @Accept json
// @Produce json
// @Param body body SSOSignIn true "SSO sign-in object"
// @Success 200 {object} store.User "User information"
// @Failure 400 {object} nil "Malformatted signin request"
// @Failure 401 {object} nil "Access denied, identifier does not match the filter."
// @Failure 403 {object} nil "User has been archived with username {username}"
// @Failure 404 {object} nil "Identity provider not found"
// @Failure 500 {object} nil "Failed to find identity provider | Failed to create identity provider instance | Failed to exchange token | Failed to get user info | Failed to compile identifier filter | Incorrect login credentials, please try again | Failed to generate random password | Failed to generate password hash | Failed to create user | Failed to generate tokens | Failed to create activity"
// @Router /api/v1/auth/signin/sso [POST]
func (s *APIV1Service) SignInSSO(c echo.Context) error {
ctx := c.Request().Context()
signin := &SSOSignIn{}
if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted signin request").SetInternal(err)
}
identityProvider, err := s.Store.GetIdentityProvider(ctx, &store.FindIdentityProvider{
ID: &signin.IdentityProviderID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find identity provider").SetInternal(err)
}
if identityProvider == nil {
return echo.NewHTTPError(http.StatusNotFound, "Identity provider not found")
}
var userInfo *idp.IdentityProviderUserInfo
if identityProvider.Type == store.IdentityProviderOAuth2Type {
oauth2IdentityProvider, err := oauth2.NewIdentityProvider(identityProvider.Config.OAuth2Config)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create identity provider instance").SetInternal(err)
}
token, err := oauth2IdentityProvider.ExchangeToken(ctx, signin.RedirectURI, signin.Code)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to exchange token").SetInternal(err)
}
userInfo, err = oauth2IdentityProvider.UserInfo(token)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get user info").SetInternal(err)
}
}
identifierFilter := identityProvider.IdentifierFilter
if identifierFilter != "" {
identifierFilterRegex, err := regexp.Compile(identifierFilter)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to compile identifier filter").SetInternal(err)
}
if !identifierFilterRegex.MatchString(userInfo.Identifier) {
return echo.NewHTTPError(http.StatusUnauthorized, "Access denied, identifier does not match the filter.").SetInternal(err)
}
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
Username: &userInfo.Identifier,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Incorrect login credentials, please try again")
}
if user == nil {
workspaceGeneralSetting, err := s.Store.GetWorkspaceGeneralSetting(ctx)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting").SetInternal(err)
}
if workspaceGeneralSetting.DisallowSignup {
return echo.NewHTTPError(http.StatusUnauthorized, "signup is disabled").SetInternal(err)
}
userCreate := &store.User{
Username: userInfo.Identifier,
// The new signup user should be normal user by default.
Role: store.RoleUser,
Nickname: userInfo.DisplayName,
Email: userInfo.Email,
}
password, err := util.RandomString(20)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate random password").SetInternal(err)
}
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err)
}
userCreate.PasswordHash = string(passwordHash)
user, err = s.Store.CreateUser(ctx, userCreate)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err)
}
}
if user.RowStatus == store.Archived {
return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with username %s", userInfo.Identifier))
}
accessToken, err := auth.GenerateAccessToken(user.Username, user.ID, time.Now().Add(auth.AccessTokenDuration), []byte(s.Secret))
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to generate tokens, err: %s", err)).SetInternal(err)
}
if err := s.UpsertAccessTokenToStore(ctx, user, accessToken); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to upsert access token, err: %s", err)).SetInternal(err)
}
cookieExp := time.Now().Add(auth.CookieExpDuration)
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
userMessage := convertUserFromStore(user)
return c.JSON(http.StatusOK, userMessage)
}
// SignOut godoc // SignOut godoc
// //
// @Summary Sign-out from memos. // @Summary Sign-out from memos.

View File

@ -1,349 +0,0 @@
package v1
import (
"encoding/json"
"fmt"
"net/http"
"github.com/labstack/echo/v4"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/store"
)
type IdentityProviderType string
const (
IdentityProviderOAuth2Type IdentityProviderType = "OAUTH2"
)
func (t IdentityProviderType) String() string {
return string(t)
}
type IdentityProviderConfig struct {
OAuth2Config *IdentityProviderOAuth2Config `json:"oauth2Config"`
}
type IdentityProviderOAuth2Config struct {
ClientID string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
AuthURL string `json:"authUrl"`
TokenURL string `json:"tokenUrl"`
UserInfoURL string `json:"userInfoUrl"`
Scopes []string `json:"scopes"`
FieldMapping *FieldMapping `json:"fieldMapping"`
}
type FieldMapping struct {
Identifier string `json:"identifier"`
DisplayName string `json:"displayName"`
Email string `json:"email"`
}
type IdentityProvider struct {
ID int32 `json:"id"`
Name string `json:"name"`
Type IdentityProviderType `json:"type"`
IdentifierFilter string `json:"identifierFilter"`
Config *IdentityProviderConfig `json:"config"`
}
type CreateIdentityProviderRequest struct {
Name string `json:"name"`
Type IdentityProviderType `json:"type"`
IdentifierFilter string `json:"identifierFilter"`
Config *IdentityProviderConfig `json:"config"`
}
type UpdateIdentityProviderRequest struct {
ID int32 `json:"-"`
Type IdentityProviderType `json:"type"`
Name *string `json:"name"`
IdentifierFilter *string `json:"identifierFilter"`
Config *IdentityProviderConfig `json:"config"`
}
func (s *APIV1Service) registerIdentityProviderRoutes(g *echo.Group) {
g.GET("/idp", s.GetIdentityProviderList)
g.POST("/idp", s.CreateIdentityProvider)
g.GET("/idp/:idpId", s.GetIdentityProvider)
g.PATCH("/idp/:idpId", s.UpdateIdentityProvider)
g.DELETE("/idp/:idpId", s.DeleteIdentityProvider)
}
// GetIdentityProviderList godoc
//
// @Summary Get a list of identity providers
// @Description *clientSecret is only available for host user
// @Tags idp
// @Produce json
// @Success 200 {object} []IdentityProvider "List of available identity providers"
// @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user"
// @Router /api/v1/idp [GET]
func (s *APIV1Service) GetIdentityProviderList(c echo.Context) error {
ctx := c.Request().Context()
list, err := s.Store.ListIdentityProviders(ctx, &store.FindIdentityProvider{})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find identity provider list").SetInternal(err)
}
userID, ok := c.Get(userIDContextKey).(int32)
isHostUser := false
if ok {
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
}
if user == nil || user.Role == store.RoleHost {
isHostUser = true
}
}
identityProviderList := []*IdentityProvider{}
for _, item := range list {
identityProvider := convertIdentityProviderFromStore(item)
// data desensitize
if !isHostUser {
identityProvider.Config.OAuth2Config.ClientSecret = ""
}
identityProviderList = append(identityProviderList, identityProvider)
}
return c.JSON(http.StatusOK, identityProviderList)
}
// CreateIdentityProvider godoc
//
// @Summary Create Identity Provider
// @Tags idp
// @Accept json
// @Produce json
// @Param body body CreateIdentityProviderRequest true "Identity provider information"
// @Success 200 {object} store.IdentityProvider "Identity provider information"
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 400 {object} nil "Malformatted post identity provider request"
// @Failure 500 {object} nil "Failed to find user | Failed to create identity provider"
// @Router /api/v1/idp [POST]
func (s *APIV1Service) CreateIdentityProvider(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(userIDContextKey).(int32)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
}
if user == nil || user.Role != store.RoleHost {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
identityProviderCreate := &CreateIdentityProviderRequest{}
if err := json.NewDecoder(c.Request().Body).Decode(identityProviderCreate); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post identity provider request").SetInternal(err)
}
identityProvider, err := s.Store.CreateIdentityProvider(ctx, &store.IdentityProvider{
Name: identityProviderCreate.Name,
Type: store.IdentityProviderType(identityProviderCreate.Type),
IdentifierFilter: identityProviderCreate.IdentifierFilter,
Config: convertIdentityProviderConfigToStore(identityProviderCreate.Config),
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create identity provider").SetInternal(err)
}
return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider))
}
// GetIdentityProvider godoc
//
// @Summary Get an identity provider by ID
// @Tags idp
// @Accept json
// @Produce json
// @Param idpId path int true "Identity provider ID"
// @Success 200 {object} store.IdentityProvider "Requested identity provider"
// @Failure 400 {object} nil "ID is not a number: %s"
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 404 {object} nil "Identity provider not found"
// @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user"
// @Router /api/v1/idp/{idpId} [GET]
func (s *APIV1Service) GetIdentityProvider(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(userIDContextKey).(int32)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
}
if user == nil || user.Role != store.RoleHost {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
identityProviderID, err := util.ConvertStringToInt32(c.Param("idpId"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("idpId"))).SetInternal(err)
}
identityProvider, err := s.Store.GetIdentityProvider(ctx, &store.FindIdentityProvider{
ID: &identityProviderID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get identity provider").SetInternal(err)
}
if identityProvider == nil {
return echo.NewHTTPError(http.StatusNotFound, "Identity provider not found")
}
return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider))
}
// DeleteIdentityProvider godoc
//
// @Summary Delete an identity provider by ID
// @Tags idp
// @Accept json
// @Produce json
// @Param idpId path int true "Identity Provider ID"
// @Success 200 {boolean} true "Identity Provider deleted"
// @Failure 400 {object} nil "ID is not a number: %s | Malformatted patch identity provider request"
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider"
// @Router /api/v1/idp/{idpId} [DELETE]
func (s *APIV1Service) DeleteIdentityProvider(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(userIDContextKey).(int32)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
}
if user == nil || user.Role != store.RoleHost {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
identityProviderID, err := util.ConvertStringToInt32(c.Param("idpId"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("idpId"))).SetInternal(err)
}
if err = s.Store.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ID: identityProviderID}); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete identity provider").SetInternal(err)
}
return c.JSON(http.StatusOK, true)
}
// UpdateIdentityProvider godoc
//
// @Summary Update an identity provider by ID
// @Tags idp
// @Accept json
// @Produce json
// @Param idpId path int true "Identity Provider ID"
// @Param body body UpdateIdentityProviderRequest true "Patched identity provider information"
// @Success 200 {object} store.IdentityProvider "Patched identity provider"
// @Failure 400 {object} nil "ID is not a number: %s | Malformatted patch identity provider request"
// @Failure 401 {object} nil "Missing user in session | Unauthorized
// @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider"
// @Router /api/v1/idp/{idpId} [PATCH]
func (s *APIV1Service) UpdateIdentityProvider(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(userIDContextKey).(int32)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
}
if user == nil || user.Role != store.RoleHost {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
identityProviderID, err := util.ConvertStringToInt32(c.Param("idpId"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("idpId"))).SetInternal(err)
}
identityProviderPatch := &UpdateIdentityProviderRequest{
ID: identityProviderID,
}
if err := json.NewDecoder(c.Request().Body).Decode(identityProviderPatch); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch identity provider request").SetInternal(err)
}
identityProvider, err := s.Store.UpdateIdentityProvider(ctx, &store.UpdateIdentityProvider{
ID: identityProviderPatch.ID,
Type: store.IdentityProviderType(identityProviderPatch.Type),
Name: identityProviderPatch.Name,
IdentifierFilter: identityProviderPatch.IdentifierFilter,
Config: convertIdentityProviderConfigToStore(identityProviderPatch.Config),
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch identity provider").SetInternal(err)
}
return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider))
}
func convertIdentityProviderFromStore(identityProvider *store.IdentityProvider) *IdentityProvider {
return &IdentityProvider{
ID: identityProvider.ID,
Name: identityProvider.Name,
Type: IdentityProviderType(identityProvider.Type),
IdentifierFilter: identityProvider.IdentifierFilter,
Config: convertIdentityProviderConfigFromStore(identityProvider.Config),
}
}
func convertIdentityProviderConfigFromStore(config *store.IdentityProviderConfig) *IdentityProviderConfig {
return &IdentityProviderConfig{
OAuth2Config: &IdentityProviderOAuth2Config{
ClientID: config.OAuth2Config.ClientID,
ClientSecret: config.OAuth2Config.ClientSecret,
AuthURL: config.OAuth2Config.AuthURL,
TokenURL: config.OAuth2Config.TokenURL,
UserInfoURL: config.OAuth2Config.UserInfoURL,
Scopes: config.OAuth2Config.Scopes,
FieldMapping: &FieldMapping{
Identifier: config.OAuth2Config.FieldMapping.Identifier,
DisplayName: config.OAuth2Config.FieldMapping.DisplayName,
Email: config.OAuth2Config.FieldMapping.Email,
},
},
}
}
func convertIdentityProviderConfigToStore(config *IdentityProviderConfig) *store.IdentityProviderConfig {
return &store.IdentityProviderConfig{
OAuth2Config: &store.IdentityProviderOAuth2Config{
ClientID: config.OAuth2Config.ClientID,
ClientSecret: config.OAuth2Config.ClientSecret,
AuthURL: config.OAuth2Config.AuthURL,
TokenURL: config.OAuth2Config.TokenURL,
UserInfoURL: config.OAuth2Config.UserInfoURL,
Scopes: config.OAuth2Config.Scopes,
FieldMapping: &store.FieldMapping{
Identifier: config.OAuth2Config.FieldMapping.Identifier,
DisplayName: config.OAuth2Config.FieldMapping.DisplayName,
Email: config.OAuth2Config.FieldMapping.Email,
},
},
}
}

View File

@ -68,7 +68,6 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) {
s.registerSystemRoutes(apiV1Group) s.registerSystemRoutes(apiV1Group)
s.registerSystemSettingRoutes(apiV1Group) s.registerSystemSettingRoutes(apiV1Group)
s.registerAuthRoutes(apiV1Group) s.registerAuthRoutes(apiV1Group)
s.registerIdentityProviderRoutes(apiV1Group)
s.registerUserRoutes(apiV1Group) s.registerUserRoutes(apiV1Group)
s.registerTagRoutes(apiV1Group) s.registerTagRoutes(apiV1Group)
s.registerStorageRoutes(apiV1Group) s.registerStorageRoutes(apiV1Group)

View File

@ -4,6 +4,8 @@ var authenticationAllowlistMethods = map[string]bool{
"/memos.api.v2.WorkspaceService/GetWorkspaceProfile": true, "/memos.api.v2.WorkspaceService/GetWorkspaceProfile": true,
"/memos.api.v2.WorkspaceSettingService/GetWorkspaceSetting": true, "/memos.api.v2.WorkspaceSettingService/GetWorkspaceSetting": true,
"/memos.api.v2.WorkspaceSettingService/ListWorkspaceSettings": true, "/memos.api.v2.WorkspaceSettingService/ListWorkspaceSettings": true,
"/memos.api.v2.IdentityProviderService/ListIdentityProviders": true,
"/memos.api.v2.IdentityProviderService/GetIdentityProvider": true,
"/memos.api.v2.AuthService/GetAuthStatus": true, "/memos.api.v2.AuthService/GetAuthStatus": true,
"/memos.api.v2.AuthService/SignIn": true, "/memos.api.v2.AuthService/SignIn": true,
"/memos.api.v2.AuthService/SignInWithSSO": true, "/memos.api.v2.AuthService/SignInWithSSO": true,

View File

@ -181,42 +181,42 @@ paths:
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.clientId - name: identityProvider.config.oauth2Config.clientId
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.clientSecret - name: identityProvider.config.oauth2Config.clientSecret
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.authUrl - name: identityProvider.config.oauth2Config.authUrl
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.tokenUrl - name: identityProvider.config.oauth2Config.tokenUrl
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.userInfoUrl - name: identityProvider.config.oauth2Config.userInfoUrl
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.scopes - name: identityProvider.config.oauth2Config.scopes
in: query in: query
required: false required: false
type: array type: array
items: items:
type: string type: string
collectionFormat: multi collectionFormat: multi
- name: identityProvider.config.oauth2.fieldMapping.identifier - name: identityProvider.config.oauth2Config.fieldMapping.identifier
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.fieldMapping.displayName - name: identityProvider.config.oauth2Config.fieldMapping.displayName
in: query in: query
required: false required: false
type: string type: string
- name: identityProvider.config.oauth2.fieldMapping.email - name: identityProvider.config.oauth2Config.fieldMapping.email
in: query in: query
required: false required: false
type: string type: string
@ -1070,7 +1070,7 @@ paths:
type: object type: object
properties: properties:
type: type:
$ref: '#/definitions/v2IdentityProviderType' $ref: '#/definitions/apiv2IdentityProviderType'
title: title:
type: string type: string
identifierFilter: identifierFilter:
@ -2006,11 +2006,33 @@ definitions:
type: string type: string
email: email:
type: string type: string
apiv2IdentityProvider:
type: object
properties:
name:
type: string
title: |-
The name of the identityProvider.
Format: identityProviders/{id}
type:
$ref: '#/definitions/apiv2IdentityProviderType'
title:
type: string
identifierFilter:
type: string
config:
$ref: '#/definitions/apiv2IdentityProviderConfig'
apiv2IdentityProviderConfig: apiv2IdentityProviderConfig:
type: object type: object
properties: properties:
oauth2: oauth2Config:
$ref: '#/definitions/apiv2OAuth2Config' $ref: '#/definitions/apiv2OAuth2Config'
apiv2IdentityProviderType:
type: string
enum:
- TYPE_UNSPECIFIED
- OAUTH2
default: TYPE_UNSPECIFIED
apiv2OAuth2Config: apiv2OAuth2Config:
type: object type: object
properties: properties:
@ -2293,7 +2315,7 @@ definitions:
type: object type: object
properties: properties:
identityProvider: identityProvider:
$ref: '#/definitions/v2IdentityProvider' $ref: '#/definitions/apiv2IdentityProvider'
description: The created identityProvider. description: The created identityProvider.
v2CreateMemoCommentResponse: v2CreateMemoCommentResponse:
type: object type: object
@ -2389,7 +2411,7 @@ definitions:
type: object type: object
properties: properties:
identityProvider: identityProvider:
$ref: '#/definitions/v2IdentityProvider' $ref: '#/definitions/apiv2IdentityProvider'
description: The identityProvider. description: The identityProvider.
v2GetLinkMetadataResponse: v2GetLinkMetadataResponse:
type: object type: object
@ -2454,28 +2476,6 @@ definitions:
properties: properties:
setting: setting:
$ref: '#/definitions/apiv2WorkspaceSetting' $ref: '#/definitions/apiv2WorkspaceSetting'
v2IdentityProvider:
type: object
properties:
name:
type: string
title: |-
The name of the identityProvider.
Format: identityProviders/{id}
type:
$ref: '#/definitions/v2IdentityProviderType'
title:
type: string
identifierFilter:
type: string
config:
$ref: '#/definitions/apiv2IdentityProviderConfig'
v2IdentityProviderType:
type: string
enum:
- TYPE_UNSPECIFIED
- OAUTH2
default: TYPE_UNSPECIFIED
v2Inbox: v2Inbox:
type: object type: object
properties: properties:
@ -2530,7 +2530,7 @@ definitions:
type: array type: array
items: items:
type: object type: object
$ref: '#/definitions/v2IdentityProvider' $ref: '#/definitions/apiv2IdentityProvider'
v2ListInboxesResponse: v2ListInboxesResponse:
type: object type: object
properties: properties:
@ -2820,7 +2820,7 @@ definitions:
type: object type: object
properties: properties:
identityProvider: identityProvider:
$ref: '#/definitions/v2IdentityProvider' $ref: '#/definitions/apiv2IdentityProvider'
description: The updated identityProvider. description: The updated identityProvider.
v2UpdateInboxResponse: v2UpdateInboxResponse:
type: object type: object

View File

@ -18,6 +18,7 @@ import (
"github.com/usememos/memos/plugin/idp" "github.com/usememos/memos/plugin/idp"
"github.com/usememos/memos/plugin/idp/oauth2" "github.com/usememos/memos/plugin/idp/oauth2"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2" apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/server/route/api/auth" "github.com/usememos/memos/server/route/api/auth"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
@ -71,7 +72,7 @@ func (s *APIV2Service) SignIn(ctx context.Context, request *apiv2pb.SignInReques
} }
func (s *APIV2Service) SignInWithSSO(ctx context.Context, request *apiv2pb.SignInWithSSORequest) (*apiv2pb.SignInWithSSOResponse, error) { func (s *APIV2Service) SignInWithSSO(ctx context.Context, request *apiv2pb.SignInWithSSORequest) (*apiv2pb.SignInWithSSOResponse, error) {
identityProvider, err := s.Store.GetIdentityProvider(ctx, &store.FindIdentityProvider{ identityProvider, err := s.Store.GetIdentityProviderV1(ctx, &store.FindIdentityProvider{
ID: &request.IdpId, ID: &request.IdpId,
}) })
if err != nil { if err != nil {
@ -82,8 +83,8 @@ func (s *APIV2Service) SignInWithSSO(ctx context.Context, request *apiv2pb.SignI
} }
var userInfo *idp.IdentityProviderUserInfo var userInfo *idp.IdentityProviderUserInfo
if identityProvider.Type == store.IdentityProviderOAuth2Type { if identityProvider.Type == storepb.IdentityProvider_OAUTH2 {
oauth2IdentityProvider, err := oauth2.NewIdentityProvider(identityProvider.Config.OAuth2Config) oauth2IdentityProvider, err := oauth2.NewIdentityProvider(identityProvider.Config.GetOauth2Config())
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to create oauth2 identity provider, err: %s", err)) return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to create oauth2 identity provider, err: %s", err))
} }

View File

@ -0,0 +1,174 @@
package v2
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func (s *APIV2Service) CreateIdentityProvider(ctx context.Context, request *apiv2pb.CreateIdentityProviderRequest) (*apiv2pb.CreateIdentityProviderResponse, error) {
currentUser, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
if currentUser.Role != store.RoleHost {
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
}
identityProvider, err := s.Store.CreateIdentityProviderV1(ctx, convertIdentityProviderToStore(request.IdentityProvider))
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create identity provider, error: %+v", err)
}
return &apiv2pb.CreateIdentityProviderResponse{
IdentityProvider: convertIdentityProviderFromStore(identityProvider),
}, nil
}
func (s *APIV2Service) ListIdentityProviders(ctx context.Context, _ *apiv2pb.ListIdentityProvidersRequest) (*apiv2pb.ListIdentityProvidersResponse, error) {
identityProviders, err := s.Store.ListIdentityProvidersV1(ctx, &store.FindIdentityProvider{})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list identity providers, error: %+v", err)
}
response := &apiv2pb.ListIdentityProvidersResponse{
IdentityProviders: []*apiv2pb.IdentityProvider{},
}
for _, identityProvider := range identityProviders {
response.IdentityProviders = append(response.IdentityProviders, convertIdentityProviderFromStore(identityProvider))
}
return response, nil
}
func (s *APIV2Service) GetIdentityProvider(ctx context.Context, request *apiv2pb.GetIdentityProviderRequest) (*apiv2pb.GetIdentityProviderResponse, error) {
id, err := ExtractIdentityProviderIDFromName(request.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid identity provider name: %v", err)
}
identityProvider, err := s.Store.GetIdentityProviderV1(ctx, &store.FindIdentityProvider{
ID: &id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get identity provider, error: %+v", err)
}
if identityProvider == nil {
return nil, status.Errorf(codes.NotFound, "identity provider not found")
}
return &apiv2pb.GetIdentityProviderResponse{
IdentityProvider: convertIdentityProviderFromStore(identityProvider),
}, nil
}
func (s *APIV2Service) UpdateIdentityProvider(ctx context.Context, request *apiv2pb.UpdateIdentityProviderRequest) (*apiv2pb.UpdateIdentityProviderResponse, error) {
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "update_mask is required")
}
id, err := ExtractIdentityProviderIDFromName(request.IdentityProvider.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid identity provider name: %v", err)
}
update := &store.UpdateIdentityProviderV1{
ID: id,
Type: storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[request.IdentityProvider.Type.String()]),
}
for _, field := range request.UpdateMask.Paths {
switch field {
case "title":
update.Name = &request.IdentityProvider.Title
case "config":
update.Config = convertIdentityProviderConfigToStore(request.IdentityProvider.Type, request.IdentityProvider.Config)
}
}
identityProvider, err := s.Store.UpdateIdentityProviderV1(ctx, update)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update identity provider, error: %+v", err)
}
return &apiv2pb.UpdateIdentityProviderResponse{
IdentityProvider: convertIdentityProviderFromStore(identityProvider),
}, nil
}
func (s *APIV2Service) DeleteIdentityProvider(ctx context.Context, request *apiv2pb.DeleteIdentityProviderRequest) (*apiv2pb.DeleteIdentityProviderResponse, error) {
id, err := ExtractIdentityProviderIDFromName(request.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid identity provider name: %v", err)
}
if err := s.Store.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ID: id}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete identity provider, error: %+v", err)
}
return &apiv2pb.DeleteIdentityProviderResponse{}, nil
}
func convertIdentityProviderFromStore(identityProvider *storepb.IdentityProvider) *apiv2pb.IdentityProvider {
temp := &apiv2pb.IdentityProvider{
Name: fmt.Sprintf("%s%d", IdentityProviderNamePrefix, identityProvider.Id),
Title: identityProvider.Name,
IdentifierFilter: identityProvider.IdentifierFilter,
Type: apiv2pb.IdentityProvider_Type(apiv2pb.IdentityProvider_Type_value[identityProvider.Type.String()]),
}
if identityProvider.Type == storepb.IdentityProvider_OAUTH2 {
oauth2Config := identityProvider.Config.GetOauth2Config()
temp.Config = &apiv2pb.IdentityProviderConfig{
Config: &apiv2pb.IdentityProviderConfig_Oauth2Config{
Oauth2Config: &apiv2pb.OAuth2Config{
ClientId: oauth2Config.ClientId,
ClientSecret: oauth2Config.ClientSecret,
AuthUrl: oauth2Config.AuthUrl,
TokenUrl: oauth2Config.TokenUrl,
UserInfoUrl: oauth2Config.UserInfoUrl,
Scopes: oauth2Config.Scopes,
FieldMapping: &apiv2pb.FieldMapping{
Identifier: oauth2Config.FieldMapping.Identifier,
DisplayName: oauth2Config.FieldMapping.DisplayName,
Email: oauth2Config.FieldMapping.Email,
},
},
},
}
}
return temp
}
func convertIdentityProviderToStore(identityProvider *apiv2pb.IdentityProvider) *storepb.IdentityProvider {
id, _ := ExtractIdentityProviderIDFromName(identityProvider.Name)
temp := &storepb.IdentityProvider{
Id: id,
Name: identityProvider.Title,
IdentifierFilter: identityProvider.IdentifierFilter,
Type: storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[identityProvider.Type.String()]),
Config: convertIdentityProviderConfigToStore(identityProvider.Type, identityProvider.Config),
}
return temp
}
func convertIdentityProviderConfigToStore(identityProviderType apiv2pb.IdentityProvider_Type, config *apiv2pb.IdentityProviderConfig) *storepb.IdentityProviderConfig {
if identityProviderType == apiv2pb.IdentityProvider_OAUTH2 {
oauth2Config := config.GetOauth2Config()
return &storepb.IdentityProviderConfig{
Config: &storepb.IdentityProviderConfig_Oauth2Config{
Oauth2Config: &storepb.OAuth2Config{
ClientId: oauth2Config.ClientId,
ClientSecret: oauth2Config.ClientSecret,
AuthUrl: oauth2Config.AuthUrl,
TokenUrl: oauth2Config.TokenUrl,
UserInfoUrl: oauth2Config.UserInfoUrl,
Scopes: oauth2Config.Scopes,
FieldMapping: &storepb.FieldMapping{
Identifier: oauth2Config.FieldMapping.Identifier,
DisplayName: oauth2Config.FieldMapping.DisplayName,
Email: oauth2Config.FieldMapping.Email,
},
},
},
}
}
return nil
}

View File

@ -16,6 +16,7 @@ const (
ResourceNamePrefix = "resources/" ResourceNamePrefix = "resources/"
InboxNamePrefix = "inboxes/" InboxNamePrefix = "inboxes/"
StorageNamePrefix = "storages/" StorageNamePrefix = "storages/"
IdentityProviderNamePrefix = "identityProviders/"
) )
// GetNameParentTokens returns the tokens from a resource name. // GetNameParentTokens returns the tokens from a resource name.
@ -110,3 +111,15 @@ func ExtractStorageIDFromName(name string) (int32, error) {
} }
return id, nil return id, nil
} }
func ExtractIdentityProviderIDFromName(name string) (int32, error) {
tokens, err := GetNameParentTokens(name, IdentityProviderNamePrefix)
if err != nil {
return 0, err
}
id, err := util.ConvertStringToInt32(tokens[0])
if err != nil {
return 0, errors.Errorf("invalid identity provider ID %q", tokens[0])
}
return id, nil
}

View File

@ -105,7 +105,7 @@ func convertStorageFromStore(storage *storepb.Storage) *apiv2pb.Storage {
if storage.Type == storepb.Storage_S3 { if storage.Type == storepb.Storage_S3 {
s3Config := storage.Config.GetS3Config() s3Config := storage.Config.GetS3Config()
temp.Config = &apiv2pb.StorageConfig{ temp.Config = &apiv2pb.StorageConfig{
StorageConfig: &apiv2pb.StorageConfig_S3Config{ Config: &apiv2pb.StorageConfig_S3Config{
S3Config: &apiv2pb.S3Config{ S3Config: &apiv2pb.S3Config{
EndPoint: s3Config.EndPoint, EndPoint: s3Config.EndPoint,
Path: s3Config.Path, Path: s3Config.Path,

View File

@ -32,6 +32,7 @@ type APIV2Service struct {
apiv2pb.UnimplementedWebhookServiceServer apiv2pb.UnimplementedWebhookServiceServer
apiv2pb.UnimplementedLinkServiceServer apiv2pb.UnimplementedLinkServiceServer
apiv2pb.UnimplementedStorageServiceServer apiv2pb.UnimplementedStorageServiceServer
apiv2pb.UnimplementedIdentityProviderServiceServer
Secret string Secret string
Profile *profile.Profile Profile *profile.Profile
@ -70,6 +71,7 @@ func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store
apiv2pb.RegisterWebhookServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterWebhookServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterLinkServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterLinkServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterStorageServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterStorageServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterIdentityProviderServiceServer(grpcServer, apiv2Service)
reflection.Register(grpcServer) reflection.Register(grpcServer)
return apiv2Service return apiv2Service
@ -129,6 +131,9 @@ func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error
if err := apiv2pb.RegisterStorageServiceHandler(context.Background(), gwMux, conn); err != nil { if err := apiv2pb.RegisterStorageServiceHandler(context.Background(), gwMux, conn); err != nil {
return err return err
} }
if err := apiv2pb.RegisterIdentityProviderServiceHandler(context.Background(), gwMux, conn); err != nil {
return err
}
e.Any("/api/v2/*", echo.WrapHandler(gwMux)) e.Any("/api/v2/*", echo.WrapHandler(gwMux))
// GRPC web proxy. // GRPC web proxy.

View File

@ -2,29 +2,18 @@ package mysql
import ( import (
"context" "context"
"encoding/json"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) { func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) {
var configBytes []byte
if create.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(create.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(create.Type))
}
placeholders := []string{"?", "?", "?", "?"} placeholders := []string{"?", "?", "?", "?"}
fields := []string{"`name`", "`type`", "`identifier_filter`", "`config`"} fields := []string{"`name`", "`type`", "`identifier_filter`", "`config`"}
args := []any{create.Name, create.Type, create.IdentifierFilter, string(configBytes)} args := []any{create.Name, create.Type.String(), create.IdentifierFilter, create.Config}
stmt := "INSERT INTO `idp` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholders, ", ") + ")" stmt := "INSERT INTO `idp` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholders, ", ") + ")"
result, err := d.db.ExecContext(ctx, stmt, args...) result, err := d.db.ExecContext(ctx, stmt, args...)
@ -58,28 +47,17 @@ func (d *DB) ListIdentityProviders(ctx context.Context, find *store.FindIdentity
var identityProviders []*store.IdentityProvider var identityProviders []*store.IdentityProvider
for rows.Next() { for rows.Next() {
var identityProvider store.IdentityProvider var identityProvider store.IdentityProvider
var identityProviderConfig string var typeString string
if err := rows.Scan( if err := rows.Scan(
&identityProvider.ID, &identityProvider.ID,
&identityProvider.Name, &identityProvider.Name,
&identityProvider.Type, &typeString,
&identityProvider.IdentifierFilter, &identityProvider.IdentifierFilter,
&identityProviderConfig, &identityProvider.Config,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
identityProvider.Type = storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[typeString])
if identityProvider.Type == store.IdentityProviderOAuth2Type {
oauth2Config := &store.IdentityProviderOAuth2Config{}
if err := json.Unmarshal([]byte(identityProviderConfig), oauth2Config); err != nil {
return nil, err
}
identityProvider.Config = &store.IdentityProviderConfig{
OAuth2Config: oauth2Config,
}
} else {
return nil, errors.Errorf("unsupported idp type %s", string(identityProvider.Type))
}
identityProviders = append(identityProviders, &identityProvider) identityProviders = append(identityProviders, &identityProvider)
} }
@ -112,17 +90,7 @@ func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIde
set, args = append(set, "`identifier_filter` = ?"), append(args, *v) set, args = append(set, "`identifier_filter` = ?"), append(args, *v)
} }
if v := update.Config; v != nil { if v := update.Config; v != nil {
var configBytes []byte set, args = append(set, "`config` = ?"), append(args, *v)
if update.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(update.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(update.Type))
}
set, args = append(set, "`config` = ?"), append(args, string(configBytes))
} }
args = append(args, update.ID) args = append(args, update.ID)

View File

@ -2,28 +2,15 @@ package postgres
import ( import (
"context" "context"
"encoding/json"
"strings" "strings"
"github.com/pkg/errors" storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) { func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) {
var configBytes []byte
if create.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(create.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(create.Type))
}
fields := []string{"name", "type", "identifier_filter", "config"} fields := []string{"name", "type", "identifier_filter", "config"}
args := []any{create.Name, create.Type, create.IdentifierFilter, string(configBytes)} args := []any{create.Name, create.Type.Type(), create.IdentifierFilter, create.Config}
stmt := "INSERT INTO idp (" + strings.Join(fields, ", ") + ") VALUES (" + placeholders(len(args)) + ") RETURNING id" stmt := "INSERT INTO idp (" + strings.Join(fields, ", ") + ") VALUES (" + placeholders(len(args)) + ") RETURNING id"
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID); err != nil { if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID); err != nil {
return nil, err return nil, err
@ -58,28 +45,18 @@ func (d *DB) ListIdentityProviders(ctx context.Context, find *store.FindIdentity
var identityProviders []*store.IdentityProvider var identityProviders []*store.IdentityProvider
for rows.Next() { for rows.Next() {
var identityProvider store.IdentityProvider var identityProvider store.IdentityProvider
var identityProviderConfig string var typeString string
if err := rows.Scan( if err := rows.Scan(
&identityProvider.ID, &identityProvider.ID,
&identityProvider.Name, &identityProvider.Name,
&identityProvider.Type, &typeString,
&identityProvider.IdentifierFilter, &identityProvider.IdentifierFilter,
&identityProviderConfig, &identityProvider.Config,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
if identityProvider.Type == store.IdentityProviderOAuth2Type { identityProvider.Type = storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[typeString])
oauth2Config := &store.IdentityProviderOAuth2Config{}
if err := json.Unmarshal([]byte(identityProviderConfig), oauth2Config); err != nil {
return nil, err
}
identityProvider.Config = &store.IdentityProviderConfig{
OAuth2Config: oauth2Config,
}
} else {
return nil, errors.Errorf("unsupported idp type %s", string(identityProvider.Type))
}
identityProviders = append(identityProviders, &identityProvider) identityProviders = append(identityProviders, &identityProvider)
} }
@ -90,18 +67,6 @@ func (d *DB) ListIdentityProviders(ctx context.Context, find *store.FindIdentity
return identityProviders, nil return identityProviders, nil
} }
func (d *DB) GetIdentityProvider(ctx context.Context, find *store.FindIdentityProvider) (*store.IdentityProvider, error) {
list, err := d.ListIdentityProviders(ctx, find)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, nil
}
return list[0], nil
}
func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIdentityProvider) (*store.IdentityProvider, error) { func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIdentityProvider) (*store.IdentityProvider, error) {
set, args := []string{}, []any{} set, args := []string{}, []any{}
if v := update.Name; v != nil { if v := update.Name; v != nil {
@ -111,17 +76,7 @@ func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIde
set, args = append(set, "identifier_filter = "+placeholder(len(args)+1)), append(args, *v) set, args = append(set, "identifier_filter = "+placeholder(len(args)+1)), append(args, *v)
} }
if v := update.Config; v != nil { if v := update.Config; v != nil {
var configBytes []byte set, args = append(set, "config = "+placeholder(len(args)+1)), append(args, *v)
if update.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(update.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(update.Type))
}
set, args = append(set, "config = "+placeholder(len(args)+1)), append(args, string(configBytes))
} }
stmt := ` stmt := `
@ -133,29 +88,18 @@ func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIde
args = append(args, update.ID) args = append(args, update.ID)
var identityProvider store.IdentityProvider var identityProvider store.IdentityProvider
var identityProviderConfig string var typeString string
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan( if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(
&identityProvider.ID, &identityProvider.ID,
&identityProvider.Name, &identityProvider.Name,
&identityProvider.Type, &typeString,
&identityProvider.IdentifierFilter, &identityProvider.IdentifierFilter,
&identityProviderConfig, &identityProvider.Config,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
if identityProvider.Type == store.IdentityProviderOAuth2Type { identityProvider.Type = storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[typeString])
oauth2Config := &store.IdentityProviderOAuth2Config{}
if err := json.Unmarshal([]byte(identityProviderConfig), oauth2Config); err != nil {
return nil, err
}
identityProvider.Config = &store.IdentityProviderConfig{
OAuth2Config: oauth2Config,
}
} else {
return nil, errors.Errorf("unsupported idp type %s", string(identityProvider.Type))
}
return &identityProvider, nil return &identityProvider, nil
} }

View File

@ -2,30 +2,17 @@ package sqlite
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"strings" "strings"
"github.com/pkg/errors" storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) { func (d *DB) CreateIdentityProvider(ctx context.Context, create *store.IdentityProvider) (*store.IdentityProvider, error) {
var configBytes []byte
if create.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(create.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(create.Type))
}
placeholders := []string{"?", "?", "?", "?"} placeholders := []string{"?", "?", "?", "?"}
fields := []string{"`name`", "`type`", "`identifier_filter`", "`config`"} fields := []string{"`name`", "`type`", "`identifier_filter`", "`config`"}
args := []any{create.Name, create.Type, create.IdentifierFilter, string(configBytes)} args := []any{create.Name, create.Type.String(), create.IdentifierFilter, create.Config}
stmt := "INSERT INTO `idp` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholders, ", ") + ") RETURNING `id`" stmt := "INSERT INTO `idp` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholders, ", ") + ") RETURNING `id`"
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID); err != nil { if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID); err != nil {
@ -61,28 +48,17 @@ func (d *DB) ListIdentityProviders(ctx context.Context, find *store.FindIdentity
var identityProviders []*store.IdentityProvider var identityProviders []*store.IdentityProvider
for rows.Next() { for rows.Next() {
var identityProvider store.IdentityProvider var identityProvider store.IdentityProvider
var identityProviderConfig string var typeString string
if err := rows.Scan( if err := rows.Scan(
&identityProvider.ID, &identityProvider.ID,
&identityProvider.Name, &identityProvider.Name,
&identityProvider.Type, &typeString,
&identityProvider.IdentifierFilter, &identityProvider.IdentifierFilter,
&identityProviderConfig, &identityProvider.Config,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
identityProvider.Type = storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[typeString])
if identityProvider.Type == store.IdentityProviderOAuth2Type {
oauth2Config := &store.IdentityProviderOAuth2Config{}
if err := json.Unmarshal([]byte(identityProviderConfig), oauth2Config); err != nil {
return nil, err
}
identityProvider.Config = &store.IdentityProviderConfig{
OAuth2Config: oauth2Config,
}
} else {
return nil, errors.Errorf("unsupported idp type %s", string(identityProvider.Type))
}
identityProviders = append(identityProviders, &identityProvider) identityProviders = append(identityProviders, &identityProvider)
} }
@ -102,17 +78,7 @@ func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIde
set, args = append(set, "identifier_filter = ?"), append(args, *v) set, args = append(set, "identifier_filter = ?"), append(args, *v)
} }
if v := update.Config; v != nil { if v := update.Config; v != nil {
var configBytes []byte set, args = append(set, "config = ?"), append(args, *v)
if update.Type == store.IdentityProviderOAuth2Type {
bytes, err := json.Marshal(update.Config.OAuth2Config)
if err != nil {
return nil, err
}
configBytes = bytes
} else {
return nil, errors.Errorf("unsupported idp type %s", string(update.Type))
}
set, args = append(set, "config = ?"), append(args, string(configBytes))
} }
args = append(args, update.ID) args = append(args, update.ID)
@ -123,29 +89,17 @@ func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIde
RETURNING id, name, type, identifier_filter, config RETURNING id, name, type, identifier_filter, config
` `
var identityProvider store.IdentityProvider var identityProvider store.IdentityProvider
var identityProviderConfig string var typeString string
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan( if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(
&identityProvider.ID, &identityProvider.ID,
&identityProvider.Name, &identityProvider.Name,
&identityProvider.Type, &typeString,
&identityProvider.IdentifierFilter, &identityProvider.IdentifierFilter,
&identityProviderConfig, &identityProvider.Config,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
identityProvider.Type = storepb.IdentityProvider_Type(storepb.IdentityProvider_Type_value[typeString])
if identityProvider.Type == store.IdentityProviderOAuth2Type {
oauth2Config := &store.IdentityProviderOAuth2Config{}
if err := json.Unmarshal([]byte(identityProviderConfig), oauth2Config); err != nil {
return nil, err
}
identityProvider.Config = &store.IdentityProviderConfig{
OAuth2Config: oauth2Config,
}
} else {
return nil, errors.Errorf("unsupported idp type %s", string(identityProvider.Type))
}
return &identityProvider, nil return &identityProvider, nil
} }

View File

@ -2,44 +2,19 @@ package store
import ( import (
"context" "context"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb "github.com/usememos/memos/proto/gen/store"
) )
type IdentityProviderType string
const (
IdentityProviderOAuth2Type IdentityProviderType = "OAUTH2"
)
func (t IdentityProviderType) String() string {
return string(t)
}
type IdentityProviderConfig struct {
OAuth2Config *IdentityProviderOAuth2Config
}
type IdentityProviderOAuth2Config struct {
ClientID string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
AuthURL string `json:"authUrl"`
TokenURL string `json:"tokenUrl"`
UserInfoURL string `json:"userInfoUrl"`
Scopes []string `json:"scopes"`
FieldMapping *FieldMapping `json:"fieldMapping"`
}
type FieldMapping struct {
Identifier string `json:"identifier"`
DisplayName string `json:"displayName"`
Email string `json:"email"`
}
type IdentityProvider struct { type IdentityProvider struct {
ID int32 ID int32
Name string Name string
Type IdentityProviderType Type storepb.IdentityProvider_Type
IdentifierFilter string IdentifierFilter string
Config *IdentityProviderConfig Config string
} }
type FindIdentityProvider struct { type FindIdentityProvider struct {
@ -48,64 +23,107 @@ type FindIdentityProvider struct {
type UpdateIdentityProvider struct { type UpdateIdentityProvider struct {
ID int32 ID int32
Type IdentityProviderType
Name *string Name *string
IdentifierFilter *string IdentifierFilter *string
Config *IdentityProviderConfig Config *string
} }
type DeleteIdentityProvider struct { type DeleteIdentityProvider struct {
ID int32 ID int32
} }
func (s *Store) CreateIdentityProvider(ctx context.Context, create *IdentityProvider) (*IdentityProvider, error) { func (s *Store) CreateIdentityProviderV1(ctx context.Context, create *storepb.IdentityProvider) (*storepb.IdentityProvider, error) {
identityProvider, err := s.driver.CreateIdentityProvider(ctx, create) raw, err := convertIdentityProviderToRaw(create)
if err != nil {
return nil, err
}
identityProviderRaw, err := s.driver.CreateIdentityProvider(ctx, raw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.idpCache.Store(identityProvider.ID, identityProvider) identityProvider, err := convertIdentityProviderFromRaw(identityProviderRaw)
if err != nil {
return nil, err
}
s.idpV1Cache.Store(identityProvider.Id, identityProvider)
return identityProvider, nil return identityProvider, nil
} }
func (s *Store) ListIdentityProviders(ctx context.Context, find *FindIdentityProvider) ([]*IdentityProvider, error) { func (s *Store) ListIdentityProvidersV1(ctx context.Context, find *FindIdentityProvider) ([]*storepb.IdentityProvider, error) {
identityProviders, err := s.driver.ListIdentityProviders(ctx, find) list, err := s.driver.ListIdentityProviders(ctx, find)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, item := range identityProviders { identityProviders := []*storepb.IdentityProvider{}
s.idpCache.Store(item.ID, item) for _, raw := range list {
identityProvider, err := convertIdentityProviderFromRaw(raw)
if err != nil {
return nil, err
}
s.idpV1Cache.Store(identityProvider.Id, identityProvider)
} }
return identityProviders, nil return identityProviders, nil
} }
func (s *Store) GetIdentityProvider(ctx context.Context, find *FindIdentityProvider) (*IdentityProvider, error) { func (s *Store) GetIdentityProviderV1(ctx context.Context, find *FindIdentityProvider) (*storepb.IdentityProvider, error) {
if find.ID != nil { if find.ID != nil {
if cache, ok := s.idpCache.Load(*find.ID); ok { if cache, ok := s.idpV1Cache.Load(*find.ID); ok {
return cache.(*IdentityProvider), nil return cache.(*storepb.IdentityProvider), nil
} }
} }
list, err := s.ListIdentityProviders(ctx, find) list, err := s.ListIdentityProvidersV1(ctx, find)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(list) == 0 { if len(list) == 0 {
return nil, nil return nil, nil
} }
if len(list) > 1 {
return nil, errors.Errorf("Found multiple identity providers with ID %d", *find.ID)
}
identityProvider := list[0] identityProvider := list[0]
return identityProvider, nil return identityProvider, nil
} }
func (s *Store) UpdateIdentityProvider(ctx context.Context, update *UpdateIdentityProvider) (*IdentityProvider, error) { type UpdateIdentityProviderV1 struct {
identityProvider, err := s.driver.UpdateIdentityProvider(ctx, update) ID int32
Type storepb.IdentityProvider_Type
Name *string
IdentifierFilter *string
Config *storepb.IdentityProviderConfig
}
func (s *Store) UpdateIdentityProviderV1(ctx context.Context, update *UpdateIdentityProviderV1) (*storepb.IdentityProvider, error) {
updateRaw := &UpdateIdentityProvider{
ID: update.ID,
}
if update.Name != nil {
updateRaw.Name = update.Name
}
if update.IdentifierFilter != nil {
updateRaw.IdentifierFilter = update.IdentifierFilter
}
if update.Config != nil {
configRaw, err := convertIdentityProviderConfigToRaw(update.Type, update.Config)
if err != nil {
return nil, err
}
updateRaw.Config = &configRaw
}
identityProviderRaw, err := s.driver.UpdateIdentityProvider(ctx, updateRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.idpCache.Store(identityProvider.ID, identityProvider) identityProvider, err := convertIdentityProviderFromRaw(identityProviderRaw)
if err != nil {
return nil, err
}
s.idpV1Cache.Store(identityProvider.Id, identityProvider)
return identityProvider, nil return identityProvider, nil
} }
@ -118,3 +136,57 @@ func (s *Store) DeleteIdentityProvider(ctx context.Context, delete *DeleteIdenti
s.idpCache.Delete(delete.ID) s.idpCache.Delete(delete.ID)
return nil return nil
} }
func convertIdentityProviderFromRaw(raw *IdentityProvider) (*storepb.IdentityProvider, error) {
identityProvider := &storepb.IdentityProvider{
Id: raw.ID,
Name: raw.Name,
Type: raw.Type,
IdentifierFilter: raw.IdentifierFilter,
}
config, err := convertIdentityProviderConfigFromRaw(identityProvider.Type, raw.Config)
if err != nil {
return nil, err
}
identityProvider.Config = config
return identityProvider, nil
}
func convertIdentityProviderToRaw(identityProvider *storepb.IdentityProvider) (*IdentityProvider, error) {
raw := &IdentityProvider{
ID: identityProvider.Id,
Name: identityProvider.Name,
Type: identityProvider.Type,
IdentifierFilter: identityProvider.IdentifierFilter,
}
configRaw, err := convertIdentityProviderConfigToRaw(identityProvider.Type, identityProvider.Config)
if err != nil {
return nil, err
}
raw.Config = configRaw
return raw, nil
}
func convertIdentityProviderConfigFromRaw(identityProviderType storepb.IdentityProvider_Type, raw string) (*storepb.IdentityProviderConfig, error) {
config := &storepb.IdentityProviderConfig{}
if identityProviderType == storepb.IdentityProvider_OAUTH2 {
oauth2Config := &storepb.OAuth2Config{}
if err := protojsonUnmarshaler.Unmarshal([]byte(raw), oauth2Config); err != nil {
return nil, errors.Wrap(err, "Failed to unmarshal OAuth2Config")
}
config.Config = &storepb.IdentityProviderConfig_Oauth2Config{Oauth2Config: oauth2Config}
}
return config, nil
}
func convertIdentityProviderConfigToRaw(identityProviderType storepb.IdentityProvider_Type, config *storepb.IdentityProviderConfig) (string, error) {
raw := ""
if identityProviderType == storepb.IdentityProvider_OAUTH2 {
bytes, err := protojson.Marshal(config.GetOauth2Config())
if err != nil {
return "", errors.Wrap(err, "Failed to marshal OAuth2Config")
}
raw = string(bytes)
}
return raw, nil
}

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/encoding/protojson"
storepb "github.com/usememos/memos/proto/gen/store" storepb "github.com/usememos/memos/proto/gen/store"
) )
@ -65,7 +65,7 @@ func (s *Store) CreateStorageV1(ctx context.Context, create *storepb.Storage) (*
} }
if create.Type == storepb.Storage_S3 { if create.Type == storepb.Storage_S3 {
configBytes, err := proto.Marshal(create.Config.GetS3Config()) configBytes, err := protojson.Marshal(create.Config.GetS3Config())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to marshal s3 config") return nil, errors.Wrap(err, "failed to marshal s3 config")
} }
@ -174,7 +174,7 @@ func convertStorageConfigFromRaw(storageType storepb.Storage_Type, configRaw str
func convertStorageConfigToRaw(storageType storepb.Storage_Type, config *storepb.StorageConfig) (string, error) { func convertStorageConfigToRaw(storageType storepb.Storage_Type, config *storepb.StorageConfig) (string, error) {
raw := "" raw := ""
if storageType == storepb.Storage_S3 { if storageType == storepb.Storage_S3 {
bytes, err := proto.Marshal(config.GetS3Config()) bytes, err := protojson.Marshal(config.GetS3Config())
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -9,13 +9,13 @@ import (
// Store provides database access to all raw objects. // Store provides database access to all raw objects.
type Store struct { type Store struct {
Profile *profile.Profile Profile *profile.Profile
driver Driver driver Driver
workspaceSettingCache sync.Map // map[string]*WorkspaceSetting workspaceSettingCache sync.Map // map[string]*storepb.WorkspaceSetting
workspaceSettingV1Cache sync.Map // map[string]*storepb.WorkspaceSetting userCache sync.Map // map[int]*User
userCache sync.Map // map[int]*User userSettingCache sync.Map // map[string]*UserSetting
userSettingCache sync.Map // map[string]*UserSetting idpCache sync.Map // map[int]*IdentityProvider
idpCache sync.Map // map[int]*IdentityProvider idpV1Cache sync.Map // map[int]*storepb.IdentityProvider
} }
// New creates a new instance of Store. // New creates a new instance of Store.

View File

@ -32,20 +32,10 @@ func (s *Store) ListWorkspaceSettings(ctx context.Context, find *FindWorkspaceSe
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, systemSettingMessage := range list {
s.workspaceSettingCache.Store(systemSettingMessage.Name, systemSettingMessage)
}
return list, nil return list, nil
} }
func (s *Store) GetWorkspaceSetting(ctx context.Context, find *FindWorkspaceSetting) (*WorkspaceSetting, error) { func (s *Store) GetWorkspaceSetting(ctx context.Context, find *FindWorkspaceSetting) (*WorkspaceSetting, error) {
if find.Name != "" {
if cache, ok := s.workspaceSettingCache.Load(find.Name); ok {
return cache.(*WorkspaceSetting), nil
}
}
list, err := s.ListWorkspaceSettings(ctx, find) list, err := s.ListWorkspaceSettings(ctx, find)
if err != nil { if err != nil {
return nil, err return nil, err
@ -56,7 +46,6 @@ func (s *Store) GetWorkspaceSetting(ctx context.Context, find *FindWorkspaceSett
} }
systemSettingMessage := list[0] systemSettingMessage := list[0]
s.workspaceSettingCache.Store(systemSettingMessage.Name, systemSettingMessage)
return systemSettingMessage, nil return systemSettingMessage, nil
} }
@ -65,7 +54,6 @@ func (s *Store) DeleteWorkspaceSetting(ctx context.Context, delete *DeleteWorksp
if err != nil { if err != nil {
return errors.Wrap(err, "Failed to delete workspace setting") return errors.Wrap(err, "Failed to delete workspace setting")
} }
s.workspaceSettingCache.Delete(delete.Name)
return nil return nil
} }
@ -101,7 +89,7 @@ func (s *Store) UpsertWorkspaceSettingV1(ctx context.Context, upsert *storepb.Wo
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed to convert workspace setting") return nil, errors.Wrap(err, "Failed to convert workspace setting")
} }
s.workspaceSettingV1Cache.Store(workspaceSetting.Key.String(), workspaceSetting) s.workspaceSettingCache.Store(workspaceSetting.Key.String(), workspaceSetting)
return workspaceSetting, nil return workspaceSetting, nil
} }
@ -117,14 +105,14 @@ func (s *Store) ListWorkspaceSettingsV1(ctx context.Context, find *FindWorkspace
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Failed to convert workspace setting") return nil, errors.Wrap(err, "Failed to convert workspace setting")
} }
s.workspaceSettingV1Cache.Store(workspaceSetting.Key.String(), workspaceSetting) s.workspaceSettingCache.Store(workspaceSetting.Key.String(), workspaceSetting)
workspaceSettings = append(workspaceSettings, workspaceSetting) workspaceSettings = append(workspaceSettings, workspaceSetting)
} }
return workspaceSettings, nil return workspaceSettings, nil
} }
func (s *Store) GetWorkspaceSettingV1(ctx context.Context, find *FindWorkspaceSetting) (*storepb.WorkspaceSetting, error) { func (s *Store) GetWorkspaceSettingV1(ctx context.Context, find *FindWorkspaceSetting) (*storepb.WorkspaceSetting, error) {
if cache, ok := s.workspaceSettingV1Cache.Load(find.Name); ok { if cache, ok := s.workspaceSettingCache.Load(find.Name); ok {
return cache.(*storepb.WorkspaceSetting), nil return cache.(*storepb.WorkspaceSetting), nil
} }

View File

@ -6,51 +6,54 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
func TestIdentityProviderStore(t *testing.T) { func TestIdentityProviderStore(t *testing.T) {
ctx := context.Background() ctx := context.Background()
ts := NewTestingStore(ctx, t) ts := NewTestingStore(ctx, t)
createdIDP, err := ts.CreateIdentityProvider(ctx, &store.IdentityProvider{ createdIDP, err := ts.CreateIdentityProviderV1(ctx, &storepb.IdentityProvider{
Name: "GitHub OAuth", Name: "GitHub OAuth",
Type: store.IdentityProviderOAuth2Type, Type: storepb.IdentityProvider_OAUTH2,
IdentifierFilter: "", IdentifierFilter: "",
Config: &store.IdentityProviderConfig{ Config: &storepb.IdentityProviderConfig{
OAuth2Config: &store.IdentityProviderOAuth2Config{ Config: &storepb.IdentityProviderConfig_Oauth2Config{
ClientID: "client_id", Oauth2Config: &storepb.OAuth2Config{
ClientSecret: "client_secret", ClientId: "client_id",
AuthURL: "https://github.com/auth", ClientSecret: "client_secret",
TokenURL: "https://github.com/token", AuthUrl: "https://github.com/auth",
UserInfoURL: "https://github.com/user", TokenUrl: "https://github.com/token",
Scopes: []string{"login"}, UserInfoUrl: "https://github.com/user",
FieldMapping: &store.FieldMapping{ Scopes: []string{"login"},
Identifier: "login", FieldMapping: &storepb.FieldMapping{
DisplayName: "name", Identifier: "login",
Email: "emai", DisplayName: "name",
Email: "email",
},
}, },
}, },
}, },
}) })
require.NoError(t, err) require.NoError(t, err)
idp, err := ts.GetIdentityProvider(ctx, &store.FindIdentityProvider{ idp, err := ts.GetIdentityProviderV1(ctx, &store.FindIdentityProvider{
ID: &createdIDP.ID, ID: &createdIDP.Id,
}) })
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, idp) require.NotNil(t, idp)
require.Equal(t, createdIDP, idp) require.Equal(t, createdIDP, idp)
newName := "My GitHub OAuth" newName := "My GitHub OAuth"
updatedIdp, err := ts.UpdateIdentityProvider(ctx, &store.UpdateIdentityProvider{ updatedIdp, err := ts.UpdateIdentityProviderV1(ctx, &store.UpdateIdentityProviderV1{
ID: idp.ID, ID: idp.Id,
Name: &newName, Name: &newName,
}) })
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, newName, updatedIdp.Name) require.Equal(t, newName, updatedIdp.Name)
err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{ err = ts.DeleteIdentityProvider(ctx, &store.DeleteIdentityProvider{
ID: idp.ID, ID: idp.Id,
}) })
require.NoError(t, err) require.NoError(t, err)
idpList, err := ts.ListIdentityProviders(ctx, &store.FindIdentityProvider{}) idpList, err := ts.ListIdentityProvidersV1(ctx, &store.FindIdentityProvider{})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 0, len(idpList)) require.Equal(t, 0, len(idpList))
ts.Close() ts.Close()

View File

@ -14,7 +14,6 @@
"@matejmazur/react-katex": "^3.1.3", "@matejmazur/react-katex": "^3.1.3",
"@mui/joy": "5.0.0-beta.32", "@mui/joy": "5.0.0-beta.32",
"@reduxjs/toolkit": "^2.2.3", "@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"copy-to-clipboard": "^3.3.3", "copy-to-clipboard": "^3.3.3",
"fuse.js": "^7.0.0", "fuse.js": "^7.0.0",

View File

@ -23,9 +23,6 @@ dependencies:
'@reduxjs/toolkit': '@reduxjs/toolkit':
specifier: ^2.2.3 specifier: ^2.2.3
version: 2.2.3(react-redux@9.1.0)(react@18.2.0) version: 2.2.3(react-redux@9.1.0)(react@18.2.0)
axios:
specifier: ^1.6.8
version: 1.6.8
classnames: classnames:
specifier: ^2.5.1 specifier: ^2.5.1
version: 2.5.1 version: 2.5.1
@ -2048,10 +2045,6 @@ packages:
is-shared-array-buffer: 1.0.3 is-shared-array-buffer: 1.0.3
dev: true dev: true
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/autoprefixer@10.4.19(postcss@8.4.38): /autoprefixer@10.4.19(postcss@8.4.38):
resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -2075,16 +2068,6 @@ packages:
possible-typed-array-names: 1.0.0 possible-typed-array-names: 1.0.0
dev: true dev: true
/axios@1.6.8:
resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==}
dependencies:
follow-redirects: 1.15.6
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/babel-plugin-macros@3.1.0: /babel-plugin-macros@3.1.0:
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
engines: {node: '>=10', npm: '>=6'} engines: {node: '>=10', npm: '>=6'}
@ -2216,13 +2199,6 @@ packages:
/color-name@1.1.4: /color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/commander@4.1.1: /commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -2681,11 +2657,6 @@ packages:
robust-predicates: 3.0.2 robust-predicates: 3.0.2
dev: false dev: false
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/dequal@2.0.3: /dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -3159,16 +3130,6 @@ packages:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
dev: true dev: true
/follow-redirects@1.15.6:
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/for-each@0.3.3: /for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies: dependencies:
@ -3183,15 +3144,6 @@ packages:
signal-exit: 4.1.0 signal-exit: 4.1.0
dev: false dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/fraction.js@4.3.7: /fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
dev: true dev: true
@ -4142,18 +4094,6 @@ packages:
braces: 3.0.2 braces: 3.0.2
picomatch: 2.3.1 picomatch: 2.3.1
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/mime@1.6.0: /mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -4564,10 +4504,6 @@ packages:
long: 5.2.3 long: 5.2.3
dev: true dev: true
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/prr@1.0.1: /prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
requiresBuild: true requiresBuild: true

View File

@ -1,18 +1,18 @@
import { Button, Divider, IconButton, Input, Option, Select, Typography } from "@mui/joy"; import { Button, Divider, IconButton, Input, Option, Select, Typography } from "@mui/joy";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import * as api from "@/helpers/api"; import { identityProviderServiceClient } from "@/grpcweb";
import { UNKNOWN_ID } from "@/helpers/consts";
import { absolutifyLink } from "@/helpers/utils"; import { absolutifyLink } from "@/helpers/utils";
import { FieldMapping, IdentityProvider, IdentityProvider_Type, OAuth2Config } from "@/types/proto/api/v2/idp_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { generateDialog } from "./Dialog"; import { generateDialog } from "./Dialog";
import Icon from "./Icon"; import Icon from "./Icon";
const templateList: IdentityProvider[] = [ const templateList: IdentityProvider[] = [
{ {
id: UNKNOWN_ID, name: "",
name: "GitHub", title: "GitHub",
type: "OAUTH2", type: IdentityProvider_Type.OAUTH2,
identifierFilter: "", identifierFilter: "",
config: { config: {
oauth2Config: { oauth2Config: {
@ -31,9 +31,9 @@ const templateList: IdentityProvider[] = [
}, },
}, },
{ {
id: UNKNOWN_ID, name: "",
name: "GitLab", title: "GitLab",
type: "OAUTH2", type: IdentityProvider_Type.OAUTH2,
identifierFilter: "", identifierFilter: "",
config: { config: {
oauth2Config: { oauth2Config: {
@ -52,9 +52,9 @@ const templateList: IdentityProvider[] = [
}, },
}, },
{ {
id: UNKNOWN_ID, name: "",
name: "Google", title: "Google",
type: "OAUTH2", type: IdentityProvider_Type.OAUTH2,
identifierFilter: "", identifierFilter: "",
config: { config: {
oauth2Config: { oauth2Config: {
@ -73,9 +73,9 @@ const templateList: IdentityProvider[] = [
}, },
}, },
{ {
id: UNKNOWN_ID, name: "",
name: "Custom", title: "Custom",
type: "OAUTH2", type: IdentityProvider_Type.OAUTH2,
identifierFilter: "", identifierFilter: "",
config: { config: {
oauth2Config: { oauth2Config: {
@ -108,8 +108,8 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
name: "", name: "",
identifierFilter: "", identifierFilter: "",
}); });
const [type, setType] = useState<IdentityProviderType>("OAUTH2"); const [type, setType] = useState<IdentityProvider_Type>(IdentityProvider_Type.OAUTH2);
const [oauth2Config, setOAuth2Config] = useState<IdentityProviderOAuth2Config>({ const [oauth2Config, setOAuth2Config] = useState<OAuth2Config>({
clientId: "", clientId: "",
clientSecret: "", clientSecret: "",
authUrl: "", authUrl: "",
@ -133,9 +133,10 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
identifierFilter: identityProvider.identifierFilter, identifierFilter: identityProvider.identifierFilter,
}); });
setType(identityProvider.type); setType(identityProvider.type);
if (identityProvider.type === "OAUTH2") { if (identityProvider.type === IdentityProvider_Type.OAUTH2) {
setOAuth2Config(identityProvider.config.oauth2Config); const oauth2Config = OAuth2Config.fromPartial(identityProvider.config?.oauth2Config || {});
setOAuth2Scopes(identityProvider.config.oauth2Config.scopes.join(" ")); setOAuth2Config(oauth2Config);
setOAuth2Scopes(oauth2Config.scopes.join(" "));
} }
} }
}, []); }, []);
@ -145,16 +146,17 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
return; return;
} }
const template = templateList.find((t) => t.name === selectedTemplate); const template = templateList.find((t) => t.title === selectedTemplate);
if (template) { if (template) {
setBasicInfo({ setBasicInfo({
name: template.name, name: template.name,
identifierFilter: template.identifierFilter, identifierFilter: template.identifierFilter,
}); });
setType(template.type); setType(template.type);
if (template.type === "OAUTH2") { if (template.type === IdentityProvider_Type.OAUTH2) {
setOAuth2Config(template.config.oauth2Config); const oauth2Config = OAuth2Config.fromPartial(template.config?.oauth2Config || {});
setOAuth2Scopes(template.config.oauth2Config.scopes.join(" ")); setOAuth2Config(oauth2Config);
setOAuth2Scopes(oauth2Config.scopes.join(" "));
} }
} }
}, [selectedTemplate]); }, [selectedTemplate]);
@ -174,7 +176,7 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
oauth2Config.tokenUrl === "" || oauth2Config.tokenUrl === "" ||
oauth2Config.userInfoUrl === "" || oauth2Config.userInfoUrl === "" ||
oauth2Scopes === "" || oauth2Scopes === "" ||
oauth2Config.fieldMapping.identifier === "" oauth2Config.fieldMapping?.identifier === ""
) { ) {
return false; return false;
} }
@ -191,28 +193,32 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
const handleConfirmBtnClick = async () => { const handleConfirmBtnClick = async () => {
try { try {
if (isCreating) { if (isCreating) {
await api.createIdentityProvider({ await identityProviderServiceClient.createIdentityProvider({
...basicInfo, identityProvider: {
type: type, ...basicInfo,
config: { type: type,
oauth2Config: { config: {
...oauth2Config, oauth2Config: {
scopes: oauth2Scopes.split(" "), ...oauth2Config,
scopes: oauth2Scopes.split(" "),
},
}, },
}, },
}); });
toast.success(t("setting.sso-section.sso-created", { name: basicInfo.name })); toast.success(t("setting.sso-section.sso-created", { name: basicInfo.name }));
} else { } else {
await api.patchIdentityProvider({ await identityProviderServiceClient.updateIdentityProvider({
id: identityProvider.id, identityProvider: {
type: type, ...basicInfo,
...basicInfo, type: type,
config: { config: {
oauth2Config: { oauth2Config: {
...oauth2Config, ...oauth2Config,
scopes: oauth2Scopes.split(" "), scopes: oauth2Scopes.split(" "),
},
}, },
}, },
updateMask: ["title", "identifierFilter", "config"],
}); });
toast.success(t("setting.sso-section.sso-updated", { name: basicInfo.name })); toast.success(t("setting.sso-section.sso-updated", { name: basicInfo.name }));
} }
@ -226,7 +232,7 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
destroy(); destroy();
}; };
const setPartialOAuth2Config = (state: Partial<IdentityProviderOAuth2Config>) => { const setPartialOAuth2Config = (state: Partial<OAuth2Config>) => {
setOAuth2Config({ setOAuth2Config({
...oauth2Config, ...oauth2Config,
...state, ...state,
@ -259,8 +265,8 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
</Typography> </Typography>
<Select className="mb-1 h-auto w-full" value={selectedTemplate} onChange={(_, e) => setSelectedTemplate(e ?? selectedTemplate)}> <Select className="mb-1 h-auto w-full" value={selectedTemplate} onChange={(_, e) => setSelectedTemplate(e ?? selectedTemplate)}>
{templateList.map((template) => ( {templateList.map((template) => (
<Option key={template.name} value={template.name}> <Option key={template.title} value={template.title}>
{template.name} {template.title}
</Option> </Option>
))} ))}
</Select> </Select>
@ -380,8 +386,10 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
<Input <Input
className="mb-2" className="mb-2"
placeholder={t("setting.sso-section.identifier")} placeholder={t("setting.sso-section.identifier")}
value={oauth2Config.fieldMapping.identifier} value={oauth2Config.fieldMapping!.identifier}
onChange={(e) => setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, identifier: e.target.value } })} onChange={(e) =>
setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, identifier: e.target.value } as FieldMapping })
}
fullWidth fullWidth
/> />
<Typography className="!mb-1" level="body-md"> <Typography className="!mb-1" level="body-md">
@ -390,8 +398,10 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
<Input <Input
className="mb-2" className="mb-2"
placeholder={t("setting.sso-section.display-name")} placeholder={t("setting.sso-section.display-name")}
value={oauth2Config.fieldMapping.displayName} value={oauth2Config.fieldMapping!.displayName}
onChange={(e) => setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, displayName: e.target.value } })} onChange={(e) =>
setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, displayName: e.target.value } as FieldMapping })
}
fullWidth fullWidth
/> />
<Typography className="!mb-1" level="body-md"> <Typography className="!mb-1" level="body-md">
@ -400,8 +410,10 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
<Input <Input
className="mb-2" className="mb-2"
placeholder={t("common.email")} placeholder={t("common.email")}
value={oauth2Config.fieldMapping.email} value={oauth2Config.fieldMapping!.email}
onChange={(e) => setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, email: e.target.value } })} onChange={(e) =>
setPartialOAuth2Config({ fieldMapping: { ...oauth2Config.fieldMapping, email: e.target.value } as FieldMapping })
}
fullWidth fullWidth
/> />
</> </>

View File

@ -2,7 +2,8 @@ import { Button, Divider, Dropdown, List, ListItem, Menu, MenuButton, MenuItem }
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import * as api from "@/helpers/api"; import { identityProviderServiceClient } from "@/grpcweb";
import { IdentityProvider } from "@/types/proto/api/v2/idp_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import showCreateIdentityProviderDialog from "../CreateIdentityProviderDialog"; import showCreateIdentityProviderDialog from "../CreateIdentityProviderDialog";
import { showCommonDialog } from "../Dialog/CommonDialog"; import { showCommonDialog } from "../Dialog/CommonDialog";
@ -18,8 +19,8 @@ const SSOSection = () => {
}, []); }, []);
const fetchIdentityProviderList = async () => { const fetchIdentityProviderList = async () => {
const { data: identityProviderList } = await api.getIdentityProviderList(); const { identityProviders } = await identityProviderServiceClient.listIdentityProviders({});
setIdentityProviderList(identityProviderList); setIdentityProviderList(identityProviders);
}; };
const handleDeleteIdentityProvider = async (identityProvider: IdentityProvider) => { const handleDeleteIdentityProvider = async (identityProvider: IdentityProvider) => {
@ -32,10 +33,10 @@ const SSOSection = () => {
dialogName: "delete-identity-provider-dialog", dialogName: "delete-identity-provider-dialog",
onConfirm: async () => { onConfirm: async () => {
try { try {
await api.deleteIdentityProvider(identityProvider.id); await identityProviderServiceClient.deleteIdentityProvider({ name: identityProvider.name });
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
toast.error(error.response.data.message); toast.error(error.details);
} }
await fetchIdentityProviderList(); await fetchIdentityProviderList();
}, },
@ -54,12 +55,12 @@ const SSOSection = () => {
<Divider /> <Divider />
{identityProviderList.map((identityProvider) => ( {identityProviderList.map((identityProvider) => (
<div <div
key={identityProvider.id} key={identityProvider.name}
className="py-2 w-full border-b last:border-b dark:border-zinc-700 flex flex-row items-center justify-between" className="py-2 w-full border-b last:border-b dark:border-zinc-700 flex flex-row items-center justify-between"
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<p className="ml-2"> <p className="ml-2">
{identityProvider.name} {identityProvider.title}
<span className="text-sm ml-1 opacity-40">({identityProvider.type})</span> <span className="text-sm ml-1 opacity-40">({identityProvider.type})</span>
</p> </p>
</div> </div>

View File

@ -1,6 +1,7 @@
import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web"; import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web";
import { ActivityServiceDefinition } from "./types/proto/api/v2/activity_service"; import { ActivityServiceDefinition } from "./types/proto/api/v2/activity_service";
import { AuthServiceDefinition } from "./types/proto/api/v2/auth_service"; import { AuthServiceDefinition } from "./types/proto/api/v2/auth_service";
import { IdentityProviderServiceDefinition } from "./types/proto/api/v2/idp_service";
import { InboxServiceDefinition } from "./types/proto/api/v2/inbox_service"; import { InboxServiceDefinition } from "./types/proto/api/v2/inbox_service";
import { LinkServiceDefinition } from "./types/proto/api/v2/link_service"; import { LinkServiceDefinition } from "./types/proto/api/v2/link_service";
import { MemoServiceDefinition } from "./types/proto/api/v2/memo_service"; import { MemoServiceDefinition } from "./types/proto/api/v2/memo_service";
@ -44,3 +45,5 @@ export const webhookServiceClient = clientFactory.create(WebhookServiceDefinitio
export const linkServiceClient = clientFactory.create(LinkServiceDefinition, channel); export const linkServiceClient = clientFactory.create(LinkServiceDefinition, channel);
export const storageServiceClient = clientFactory.create(StorageServiceDefinition, channel); export const storageServiceClient = clientFactory.create(StorageServiceDefinition, channel);
export const identityProviderServiceClient = clientFactory.create(IdentityProviderServiceDefinition, channel);

View File

@ -1,20 +0,0 @@
import axios from "axios";
axios.defaults.baseURL = import.meta.env.VITE_API_BASE_URL || "";
axios.defaults.withCredentials = true;
export function getIdentityProviderList() {
return axios.get<IdentityProvider[]>(`/api/v1/idp`);
}
export function createIdentityProvider(identityProviderCreate: IdentityProviderCreate) {
return axios.post<IdentityProvider>(`/api/v1/idp`, identityProviderCreate);
}
export function patchIdentityProvider(identityProviderPatch: IdentityProviderPatch) {
return axios.patch<IdentityProvider>(`/api/v1/idp/${identityProviderPatch.id}`, identityProviderPatch);
}
export function deleteIdentityProvider(id: IdentityProviderId) {
return axios.delete(`/api/v1/idp/${id}`);
}

View File

@ -5,13 +5,13 @@ import { toast } from "react-hot-toast";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import AppearanceSelect from "@/components/AppearanceSelect"; import AppearanceSelect from "@/components/AppearanceSelect";
import LocaleSelect from "@/components/LocaleSelect"; import LocaleSelect from "@/components/LocaleSelect";
import { authServiceClient } from "@/grpcweb"; import { authServiceClient, identityProviderServiceClient } from "@/grpcweb";
import * as api from "@/helpers/api";
import { absolutifyLink } from "@/helpers/utils"; import { absolutifyLink } from "@/helpers/utils";
import useLoading from "@/hooks/useLoading"; import useLoading from "@/hooks/useLoading";
import useNavigateTo from "@/hooks/useNavigateTo"; import useNavigateTo from "@/hooks/useNavigateTo";
import { useCommonContext } from "@/layouts/CommonContextProvider"; import { useCommonContext } from "@/layouts/CommonContextProvider";
import { useUserStore, useWorkspaceSettingStore } from "@/store/v1"; import { extractIdentityProviderIdFromName, useUserStore, useWorkspaceSettingStore } from "@/store/v1";
import { IdentityProvider, IdentityProvider_Type } from "@/types/proto/api/v2/idp_service";
import { WorkspaceGeneralSetting } from "@/types/proto/api/v2/workspace_setting_service"; import { WorkspaceGeneralSetting } from "@/types/proto/api/v2/workspace_setting_service";
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
@ -33,8 +33,8 @@ const SignIn = () => {
useEffect(() => { useEffect(() => {
const fetchIdentityProviderList = async () => { const fetchIdentityProviderList = async () => {
const { data: identityProviderList } = await api.getIdentityProviderList(); const { identityProviders } = await identityProviderServiceClient.listIdentityProviders({});
setIdentityProviderList(identityProviderList); setIdentityProviderList(identityProviders);
}; };
fetchIdentityProviderList(); fetchIdentityProviderList();
}, []); }, []);
@ -95,10 +95,14 @@ const SignIn = () => {
}; };
const handleSignInWithIdentityProvider = async (identityProvider: IdentityProvider) => { const handleSignInWithIdentityProvider = async (identityProvider: IdentityProvider) => {
const stateQueryParameter = `auth.signin.${identityProvider.name}-${identityProvider.id}`; const stateQueryParameter = `auth.signin.${identityProvider.title}-${extractIdentityProviderIdFromName(identityProvider.name)}`;
if (identityProvider.type === "OAUTH2") { if (identityProvider.type === IdentityProvider_Type.OAUTH2) {
const redirectUri = absolutifyLink("/auth/callback"); const redirectUri = absolutifyLink("/auth/callback");
const oauth2Config = identityProvider.config.oauth2Config; const oauth2Config = identityProvider.config?.oauth2Config;
if (!oauth2Config) {
toast.error("Identity provider configuration is invalid.");
return;
}
const authUrl = `${oauth2Config.authUrl}?client_id=${ const authUrl = `${oauth2Config.authUrl}?client_id=${
oauth2Config.clientId oauth2Config.clientId
}&redirect_uri=${redirectUri}&state=${stateQueryParameter}&response_type=code&scope=${encodeURIComponent( }&redirect_uri=${redirectUri}&state=${stateQueryParameter}&response_type=code&scope=${encodeURIComponent(
@ -185,7 +189,7 @@ const SignIn = () => {
<div className="w-full flex flex-col space-y-2"> <div className="w-full flex flex-col space-y-2">
{identityProviderList.map((identityProvider) => ( {identityProviderList.map((identityProvider) => (
<Button <Button
key={identityProvider.id} key={identityProvider.name}
variant="outlined" variant="outlined"
color="neutral" color="neutral"
className="w-full" className="w-full"

View File

@ -1,7 +1,12 @@
export const WorkspaceSettingPrefix = "settings/"; export const WorkspaceSettingPrefix = "settings/";
export const UserNamePrefix = "users/"; export const UserNamePrefix = "users/";
export const MemoNamePrefix = "memos/"; export const MemoNamePrefix = "memos/";
export const IdentityProviderNamePrefix = "identityProviders/";
export const extractMemoIdFromName = (name: string) => { export const extractMemoIdFromName = (name: string) => {
return parseInt(name.split(MemoNamePrefix).pop() || "", 10); return parseInt(name.split(MemoNamePrefix).pop() || "", 10);
}; };
export const extractIdentityProviderIdFromName = (name: string) => {
return parseInt(name.split(IdentityProviderNamePrefix).pop() || "", 10);
};

View File

@ -1,46 +0,0 @@
type IdentityProviderId = number;
type IdentityProviderType = "OAUTH2";
interface FieldMapping {
identifier: string;
displayName: string;
email: string;
}
interface IdentityProviderOAuth2Config {
clientId: string;
clientSecret: string;
authUrl: string;
tokenUrl: string;
userInfoUrl: string;
scopes: string[];
fieldMapping: FieldMapping;
}
interface IdentityProviderConfig {
oauth2Config: IdentityProviderOAuth2Config;
}
interface IdentityProvider {
id: IdentityProviderId;
name: string;
type: IdentityProviderType;
identifierFilter: string;
config: IdentityProviderConfig;
}
interface IdentityProviderCreate {
name: string;
type: IdentityProviderType;
identifierFilter: string;
config: IdentityProviderConfig;
}
interface IdentityProviderPatch {
id: IdentityProviderId;
type: IdentityProviderType;
name?: string;
identifierFilter?: string;
config?: IdentityProviderConfig;
}