Merge pull request #450 from authorizerdev/fix-user-verification
fix: user verification
This commit is contained in:
commit
82f639757f
16
app/package-lock.json
generated
16
app/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^1.2.0",
|
||||
"@authorizerdev/authorizer-react": "^1.3.1",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
@ -27,9 +27,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-js": {
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-cEzEVe7AewvOwOwoettiKRCq1e5Y33k9g8fJjqAoe3B/36iNN8wnZ5qgsPPZkqhv+Cvn6huj+YWtRimfVJ6d0w==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-2.0.2.tgz",
|
||||
"integrity": "sha512-YgCtpaBDGYGMUlINFsvGNJnBtbnFG2wo66xX2i6auop52oVmKimvLpzOx8306/YddCxWhg9FljyVMp88Mbnxyw==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.1.5"
|
||||
},
|
||||
|
@ -41,11 +41,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@authorizerdev/authorizer-react": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.2.0.tgz",
|
||||
"integrity": "sha512-MtunZgh30rzY9jSADVP1DRC4sOBC82zx/yhK8O/1ufOAi7vTDZwPjDHIMrG/xWPNUYTCeFPEKpZlKyB+TH/M1w==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.3.1.tgz",
|
||||
"integrity": "sha512-X7vQMr5jtZ28z+YZOt5ISB3lOYXNszpLpWw4S6VNs7TLAd5/ZP2kPaSdDbUgIvQFyYy51DHQeGygOu3G1n0Mdw==",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-js": "^2.0.0-beta.3",
|
||||
"@authorizerdev/authorizer-js": "^2.0.2",
|
||||
"validator": "^13.11.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"author": "Lakhan Samani",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@authorizerdev/authorizer-react": "^1.2.0",
|
||||
"@authorizerdev/authorizer-react": "^1.3.1",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"esbuild": "^0.12.17",
|
||||
|
|
|
@ -33,7 +33,6 @@ export default function App() {
|
|||
...window['__authorizer__'],
|
||||
...urlProps,
|
||||
};
|
||||
console.log({ globalState });
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
|
|
786
app/yarn.lock
786
app/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -53,7 +53,7 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Basic Authentication:</Text>
|
||||
<Text fontSize="sm">Email Basic Authentication:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
|
@ -64,6 +64,19 @@ const Features = ({ variables, setVariables }: any) => {
|
|||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Mobile Basic Authentication:</Text>
|
||||
</Flex>
|
||||
<Flex justifyContent="start">
|
||||
<InputField
|
||||
variables={variables}
|
||||
setVariables={setVariables}
|
||||
inputType={SwitchInputType.DISABLE_MOBILE_BASIC_AUTHENTICATION}
|
||||
hasReversedValue
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex w="100%" justifyContent="start" alignItems="center">
|
||||
<Text fontSize="sm">Sign Up:</Text>
|
||||
|
|
|
@ -83,6 +83,7 @@ export const SwitchInputType = {
|
|||
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
|
||||
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
|
||||
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: 'DISABLE_MOBILE_BASIC_AUTHENTICATION',
|
||||
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
|
||||
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
|
||||
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
|
||||
|
@ -167,6 +168,7 @@ export interface envVarTypes {
|
|||
DISABLE_MAGIC_LINK_LOGIN: boolean;
|
||||
DISABLE_EMAIL_VERIFICATION: boolean;
|
||||
DISABLE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: boolean;
|
||||
DISABLE_SIGN_UP: boolean;
|
||||
DISABLE_STRONG_PASSWORD: boolean;
|
||||
OLD_ADMIN_SECRET: string;
|
||||
|
|
|
@ -65,6 +65,7 @@ export const EnvVariablesQuery = `
|
|||
DISABLE_MAGIC_LINK_LOGIN
|
||||
DISABLE_EMAIL_VERIFICATION
|
||||
DISABLE_BASIC_AUTHENTICATION
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION
|
||||
DISABLE_SIGN_UP
|
||||
DISABLE_STRONG_PASSWORD
|
||||
DISABLE_REDIS_FOR_ENV
|
||||
|
@ -97,6 +98,7 @@ export const UserDetailsQuery = `
|
|||
id
|
||||
email
|
||||
email_verified
|
||||
phone_number_verified
|
||||
given_name
|
||||
family_name
|
||||
middle_name
|
||||
|
|
|
@ -86,6 +86,7 @@ const Environment = () => {
|
|||
DISABLE_MAGIC_LINK_LOGIN: false,
|
||||
DISABLE_EMAIL_VERIFICATION: false,
|
||||
DISABLE_BASIC_AUTHENTICATION: false,
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: false,
|
||||
DISABLE_SIGN_UP: false,
|
||||
DISABLE_STRONG_PASSWORD: false,
|
||||
OLD_ADMIN_SECRET: '',
|
||||
|
|
|
@ -165,14 +165,25 @@ export default function Users() {
|
|||
};
|
||||
|
||||
const userVerificationHandler = async (user: userDataTypes) => {
|
||||
const { id, email } = user;
|
||||
const { id, email, phone_number } = user;
|
||||
let params = {};
|
||||
if (email) {
|
||||
params = {
|
||||
id,
|
||||
email,
|
||||
email_verified: true,
|
||||
};
|
||||
}
|
||||
if (phone_number) {
|
||||
params = {
|
||||
id,
|
||||
phone_number,
|
||||
phone_number_verified: true,
|
||||
};
|
||||
}
|
||||
const res = await client
|
||||
.mutation(UpdateUser, {
|
||||
params: {
|
||||
id,
|
||||
email,
|
||||
email_verified: true,
|
||||
},
|
||||
params,
|
||||
})
|
||||
.toPromise();
|
||||
if (res.error) {
|
||||
|
@ -298,7 +309,7 @@ export default function Users() {
|
|||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>Email</Th>
|
||||
<Th>Email / Phone</Th>
|
||||
<Th>Created At</Th>
|
||||
<Th>Signup Methods</Th>
|
||||
<Th>Roles</Th>
|
||||
|
@ -314,10 +325,15 @@ export default function Users() {
|
|||
</Thead>
|
||||
<Tbody>
|
||||
{userList.map((user: userDataTypes) => {
|
||||
const { email_verified, created_at, ...rest }: any = user;
|
||||
const {
|
||||
email_verified,
|
||||
phone_number_verified,
|
||||
created_at,
|
||||
...rest
|
||||
}: any = user;
|
||||
return (
|
||||
<Tr key={user.id} style={{ fontSize: 14 }}>
|
||||
<Td maxW="300">{user.email}</Td>
|
||||
<Td maxW="300">{user.email || user.phone_number}</Td>
|
||||
<Td>
|
||||
{dayjs(user.created_at * 1000).format('MMM DD, YYYY')}
|
||||
</Td>
|
||||
|
@ -327,9 +343,15 @@ export default function Users() {
|
|||
<Tag
|
||||
size="sm"
|
||||
variant="outline"
|
||||
colorScheme={user.email_verified ? 'green' : 'yellow'}
|
||||
colorScheme={
|
||||
user.email_verified || user.phone_number_verified
|
||||
? 'green'
|
||||
: 'yellow'
|
||||
}
|
||||
>
|
||||
{user.email_verified.toString()}
|
||||
{(
|
||||
user.email_verified || user.phone_number_verified
|
||||
).toString()}
|
||||
</Tag>
|
||||
</Td>
|
||||
<Td>
|
||||
|
@ -368,13 +390,14 @@ export default function Users() {
|
|||
</Flex>
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
{!user.email_verified && (
|
||||
<MenuItem
|
||||
onClick={() => userVerificationHandler(user)}
|
||||
>
|
||||
Verify User
|
||||
</MenuItem>
|
||||
)}
|
||||
{!user.email_verified &&
|
||||
!user.phone_number_verified && (
|
||||
<MenuItem
|
||||
onClick={() => userVerificationHandler(user)}
|
||||
>
|
||||
Verify User
|
||||
</MenuItem>
|
||||
)}
|
||||
<EditUserModal
|
||||
user={rest}
|
||||
updateUserList={updateUserList}
|
||||
|
|
2114
dashboard/yarn.lock
2114
dashboard/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -11,8 +11,8 @@ const (
|
|||
type OTP struct {
|
||||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
PhoneNumber string `gorm:"index:unique_index_phone_number,unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||
Email string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
PhoneNumber string `gorm:"index" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number"`
|
||||
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
|
||||
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
|
||||
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
|
||||
|
|
|
@ -15,7 +15,7 @@ type User struct {
|
|||
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
|
||||
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
|
||||
|
||||
Email *string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
Email *string `gorm:"index" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
|
||||
EmailVerifiedAt *int64 `json:"email_verified_at" bson:"email_verified_at" cql:"email_verified_at" dynamo:"email_verified_at"`
|
||||
Password *string `json:"password" bson:"password" cql:"password" dynamo:"password"`
|
||||
SignupMethods string `json:"signup_methods" bson:"signup_methods" cql:"signup_methods" dynamo:"signup_methods"`
|
||||
|
|
|
@ -28,7 +28,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
authenticatorsCollection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||
meta, err := authenticatorsCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
authenticators.Key = meta.Key
|
||||
authenticators.ID = meta.ID.String()
|
||||
|
@ -42,7 +42,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
collection, _ := p.db.Collection(ctx, models.Collections.Authenticators)
|
||||
meta, err := collection.UpdateDocument(ctx, authenticators.Key, authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authenticators.Key = meta.Key
|
||||
|
@ -59,7 +59,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -71,7 +71,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return authenticators, nil
|
||||
|
|
|
@ -23,7 +23,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
configCollection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
env.Key = meta.Key
|
||||
env.ID = meta.ID.String()
|
||||
|
@ -36,7 +36,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
collection, _ := p.db.Collection(ctx, models.Collections.Env)
|
||||
meta, err := collection.UpdateDocument(ctx, env.Key, env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env.Key = meta.Key
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
query := fmt.Sprintf("FOR d in %s RETURN d", models.Collections.Env)
|
||||
cursor, err := p.db.Query(ctx, query, nil)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -62,7 +62,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
|
@ -43,7 +47,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(ctx), user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Key = meta.Key
|
||||
user.ID = meta.ID.String()
|
||||
|
@ -58,7 +62,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Key = meta.Key
|
||||
|
@ -125,19 +129,19 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if user == nil {
|
||||
return user, fmt.Errorf("user not found")
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
|
@ -152,19 +156,19 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
if !cursor.HasMore() {
|
||||
if user == nil {
|
||||
return user, fmt.Errorf("user not found")
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, &user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequestRequestCollection, _ := p.db.Collection(ctx, models.Collections.VerificationRequest)
|
||||
meta, err := verificationRequestRequestCollection.CreateDocument(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
verificationRequest.Key = meta.Key
|
||||
verificationRequest.ID = meta.ID.String()
|
||||
|
@ -38,7 +38,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
@ -66,7 +66,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close()
|
||||
for {
|
||||
|
@ -78,7 +78,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
_, err := cursor.ReadDocument(ctx, &verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
|
|
@ -29,7 +29,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
|
@ -38,7 +38,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
authenticatorsMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticatorsMap)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields := "("
|
||||
|
@ -66,7 +66,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
query := fmt.Sprintf("INSERT INTO %s %s VALUES %s IF NOT EXISTS", KeySpace+"."+models.Collections.Authenticators, fields, values)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authenticators, nil
|
||||
|
@ -77,7 +77,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
|
||||
bytes, err := json.Marshal(authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
|
@ -85,7 +85,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
authenticatorsMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&authenticatorsMap)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields := ""
|
||||
|
@ -116,7 +116,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.Authenticators, updateFields, authenticators.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authenticators, nil
|
||||
|
|
|
@ -20,7 +20,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
insertEnvQuery := fmt.Sprintf("INSERT INTO %s (id, env, hash, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.Env, env.ID, env.EnvData, env.Hash, env.CreatedAt, env.UpdatedAt)
|
||||
err := p.db.Query(insertEnvQuery).Exec()
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return env, nil
|
||||
|
@ -32,7 +32,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
updateEnvQuery := fmt.Sprintf("UPDATE %s SET env = '%s', updated_at = %d WHERE id = '%s'", KeySpace+"."+models.Collections.Env, env.EnvData, env.UpdatedAt, env.ID)
|
||||
err := p.db.Query(updateEnvQuery).Exec()
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
|
@ -42,7 +46,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
|
||||
bytes, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
|
@ -51,7 +55,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
userMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&userMap)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields := "("
|
||||
|
@ -80,7 +84,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
err = p.db.Query(query).Exec()
|
||||
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
|
@ -92,7 +96,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
|
||||
bytes, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
// use decoder instead of json.Unmarshall, because it converts int64 -> float64 after unmarshalling
|
||||
decoder := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
|
@ -100,7 +104,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
userMap := map[string]interface{}{}
|
||||
err = decoder.Decode(&userMap)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateFields := ""
|
||||
|
@ -131,7 +135,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
query := fmt.Sprintf("UPDATE %s SET %s WHERE id = '%s'", KeySpace+"."+models.Collections.User, updateFields, user.ID)
|
||||
err = p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
|
|
|
@ -23,7 +23,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
query := fmt.Sprintf("INSERT INTO %s (id, jwt_token, identifier, expires_at, email, nonce, redirect_uri, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, '%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.VerificationRequest, verificationRequest.ID, verificationRequest.Token, verificationRequest.Identifier, verificationRequest.ExpiresAt, verificationRequest.Email, verificationRequest.Nonce, verificationRequest.RedirectURI, verificationRequest.CreatedAt, verificationRequest.UpdatedAt)
|
||||
err := p.db.Query(query).Exec()
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.Authenticators).Insert(authenticators.ID, authenticators, &insertOpt)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
@ -71,11 +71,11 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
|||
PositionalParameters: []interface{}{userId, authenticatorType},
|
||||
})
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.Env).Insert(env.ID, env, &insertOpt)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
PositionalParameters: []interface{}{env.EnvData, env.UpdatedAt, env.UpdatedAt, env.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -55,11 +55,11 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
ScanConsistency: gocb.QueryScanConsistencyRequestPlus,
|
||||
})
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
env.Hash = env.EncryptionKey
|
||||
return env, nil
|
||||
|
|
|
@ -50,7 +50,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.OTP).Insert(otp.ID, otp, &insertOpt)
|
||||
if err != nil {
|
||||
return otp, err
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
query := fmt.Sprintf(`UPDATE %s.%s SET otp=$1, expires_at=$2, updated_at=$3 WHERE _id=$4`, p.scopeName, models.Collections.OTP)
|
||||
|
@ -58,7 +58,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
|||
PositionalParameters: []interface{}{otp.Otp, otp.ExpiresAt, otp.UpdatedAt, otp.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return otp, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return otp, nil
|
||||
|
|
|
@ -127,7 +127,7 @@ func CreateBucketAndScope(cluster *gocb.Cluster, bucketName string, scopeName st
|
|||
if scopeName != defaultScope {
|
||||
err = bucket.Collections().CreateScope(scopeName, nil)
|
||||
if err != nil && !errors.Is(err, gocb.ErrScopeExists) {
|
||||
return bucket, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return bucket, nil
|
||||
|
|
|
@ -47,7 +47,7 @@ func (p *provider) GetTotalDocs(ctx context.Context, collection string) (int64,
|
|||
})
|
||||
queryRes.One(&totalDocs)
|
||||
if err != nil {
|
||||
return totalDocs.Total, err
|
||||
return 0, err
|
||||
}
|
||||
return totalDocs.Total, nil
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/couchbase/gocb/v2"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -23,11 +25,21 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
insertOpt := gocb.InsertOptions{
|
||||
|
@ -35,7 +47,7 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Insert(user.ID, user, &insertOpt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -48,7 +60,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.User).Upsert(user.ID, user, &upsertOpt)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -110,11 +122,11 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
PositionalParameters: []interface{}{email},
|
||||
})
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -129,11 +141,11 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
PositionalParameters: []interface{}{id},
|
||||
})
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -182,11 +194,11 @@ func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string)
|
|||
PositionalParameters: []interface{}{phoneNumber},
|
||||
})
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
err = q.One(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.VerificationRequest).Insert(verificationRequest.ID, verificationRequest, &insertOpt)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
err = queryResult.One(&verificationRequest)
|
||||
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
var verificationRequest *models.VerificationRequest
|
||||
err = queryResult.One(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ func (p *provider) AddWebhook(ctx context.Context, webhook *models.Webhook) (*mo
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.Webhook).Insert(webhook.ID, webhook, &insertOpt)
|
||||
if err != nil {
|
||||
return webhook.AsAPIWebhook(), err
|
||||
return nil, err
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func (p *provider) AddWebhookLog(ctx context.Context, webhookLog *models.Webhook
|
|||
}
|
||||
_, err := p.db.Collection(models.Collections.WebhookLog).Insert(webhookLog.ID, webhookLog, &insertOpt)
|
||||
if err != nil {
|
||||
return webhookLog.AsAPIWebhookLog(), err
|
||||
return nil, err
|
||||
}
|
||||
return webhookLog.AsAPIWebhookLog(), nil
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(authenticators).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
authenticators.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", authenticators.ID, authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return authenticators, nil
|
||||
|
@ -51,7 +51,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
|||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
env.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(env).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
env.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", env.ID, env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
iter := collection.Scan().Limit(1).Iter()
|
||||
for iter.NextWithContext(ctx, &env) {
|
||||
if env == nil {
|
||||
return env, errors.New("no documets found")
|
||||
return nil, errors.New("no documets found")
|
||||
} else {
|
||||
return env, nil
|
||||
}
|
||||
|
|
|
@ -26,20 +26,24 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(user).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -51,7 +55,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
user.UpdatedAt = time.Now().Unix()
|
||||
err := UpdateByHashKey(collection, "id", user.ID, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return user, nil
|
||||
|
@ -122,7 +126,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
user = users[0]
|
||||
return user, nil
|
||||
} else {
|
||||
return user, errors.New("no record found")
|
||||
return nil, errors.New("no record found")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +137,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
err := collection.Get("id", id).OneWithContext(ctx, &user)
|
||||
if err != nil {
|
||||
if refs.StringValue(user.Email) == "" {
|
||||
return user, errors.New("no documets found")
|
||||
return nil, errors.New("no documets found")
|
||||
} else {
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequest.UpdatedAt = time.Now().Unix()
|
||||
err := collection.Put(verificationRequest).RunWithContext(ctx)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return verificationRequest, nil
|
||||
|
@ -35,7 +35,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
}
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
return verificationRequest, nil
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ func (p *provider) GetWebhookByID(ctx context.Context, webhookID string) (*model
|
|||
return nil, err
|
||||
}
|
||||
if webhook.ID == "" {
|
||||
return webhook.AsAPIWebhook(), errors.New("no documets found")
|
||||
return nil, errors.New("no documets found")
|
||||
}
|
||||
return webhook.AsAPIWebhook(), nil
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func (p *provider) AddAuthenticator(ctx context.Context, authenticators *models.
|
|||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
_, err := authenticatorsCollection.InsertOne(ctx, authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func (p *provider) UpdateAuthenticator(ctx context.Context, authenticators *mode
|
|||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
_, err := authenticatorsCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": authenticators.ID}}, bson.M{"$set": authenticators})
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func (p *provider) GetAuthenticatorDetailsByUserId(ctx context.Context, userId s
|
|||
authenticatorsCollection := p.db.Collection(models.Collections.Authenticators, options.Collection())
|
||||
err := authenticatorsCollection.FindOne(ctx, bson.M{"user_id": userId, "method": authenticatorType}).Decode(&authenticators)
|
||||
if err != nil {
|
||||
return authenticators, err
|
||||
return nil, err
|
||||
}
|
||||
return authenticators, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddEnv(ctx context.Context, env *models.Env) (*models.Env, er
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
_, err := configCollection.InsertOne(ctx, env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func (p *provider) UpdateEnv(ctx context.Context, env *models.Env) (*models.Env,
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
_, err := configCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ func (p *provider) GetEnv(ctx context.Context) (*models.Env, error) {
|
|||
configCollection := p.db.Collection(models.Collections.Env, options.Collection())
|
||||
cursor, err := configCollection.Find(ctx, bson.M{}, options.Find())
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
for cursor.Next(nil) {
|
||||
err := cursor.Decode(&env)
|
||||
if err != nil {
|
||||
return env, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if env == nil {
|
||||
|
|
|
@ -2,12 +2,15 @@ package mongodb
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
|
@ -23,17 +26,26 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
_, err := userCollection.InsertOne(ctx, user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -44,7 +56,7 @@ func (p *provider) UpdateUser(ctx context.Context, user *models.User) (*models.U
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
_, err := userCollection.UpdateOne(ctx, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions())
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -103,7 +115,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -114,7 +126,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||
err := userCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (p *provider) AddVerificationRequest(ctx context.Context, verificationReque
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
_, err := verificationRequestCollection.InsertOne(ctx, verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ func (p *provider) GetVerificationRequestByToken(ctx context.Context, token stri
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"token": token}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return verificationRequest, nil
|
||||
|
@ -49,7 +49,7 @@ func (p *provider) GetVerificationRequestByEmail(ctx context.Context, email stri
|
|||
verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection())
|
||||
err := verificationRequestCollection.FindOne(ctx, bson.M{"email": email, "identifier": identifier}).Decode(&verificationRequest)
|
||||
if err != nil {
|
||||
return verificationRequest, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return verificationRequest, nil
|
||||
|
|
|
@ -2,12 +2,15 @@ package provider_template
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
|
@ -19,10 +22,19 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
return user, nil
|
||||
|
|
|
@ -7,33 +7,56 @@ import (
|
|||
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// UpsertOTP to add or update otp
|
||||
func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) {
|
||||
if otp.ID == "" {
|
||||
otp.ID = uuid.New().String()
|
||||
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
|
||||
if otpParam.ID == "" {
|
||||
otpParam.ID = uuid.New().String()
|
||||
}
|
||||
// check if email or phone number is present
|
||||
if otp.Email == "" && otp.PhoneNumber == "" {
|
||||
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
|
||||
return nil, errors.New("email or phone_number is required")
|
||||
}
|
||||
uniqueField := models.FieldNameEmail
|
||||
if otp.Email == "" && otp.PhoneNumber != "" {
|
||||
if otpParam.Email == "" && otpParam.PhoneNumber != "" {
|
||||
uniqueField = models.FieldNamePhoneNumber
|
||||
}
|
||||
otp.Key = otp.ID
|
||||
otp.CreatedAt = time.Now().Unix()
|
||||
otp.UpdatedAt = time.Now().Unix()
|
||||
res := p.db.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: uniqueField}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}),
|
||||
}).Create(&otp)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
var otp *models.OTP
|
||||
if uniqueField == models.FieldNameEmail {
|
||||
otp, _ = p.GetOTPByEmail(ctx, otpParam.Email)
|
||||
} else {
|
||||
otp, _ = p.GetOTPByPhoneNumber(ctx, otpParam.PhoneNumber)
|
||||
}
|
||||
shouldCreate := false
|
||||
if otp == nil {
|
||||
id := uuid.NewString()
|
||||
otp = &models.OTP{
|
||||
ID: id,
|
||||
Key: id,
|
||||
Otp: otpParam.Otp,
|
||||
Email: otpParam.Email,
|
||||
PhoneNumber: otpParam.PhoneNumber,
|
||||
ExpiresAt: otpParam.ExpiresAt,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
}
|
||||
shouldCreate = true
|
||||
} else {
|
||||
otp.Otp = otpParam.Otp
|
||||
otp.ExpiresAt = otpParam.ExpiresAt
|
||||
}
|
||||
otp.UpdatedAt = time.Now().Unix()
|
||||
if shouldCreate {
|
||||
result := p.db.Create(&otp)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
} else {
|
||||
result := p.db.Save(&otp)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
}
|
||||
|
||||
return otp, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// AddUser to save user information in database
|
||||
|
@ -25,25 +24,25 @@ func (p *provider) AddUser(ctx context.Context, user *models.User) (*models.User
|
|||
if user.Roles == "" {
|
||||
defaultRoles, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||
if err != nil {
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
user.Roles = defaultRoles
|
||||
}
|
||||
|
||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given phone number already exists")
|
||||
}
|
||||
} else if user.Email != nil && strings.TrimSpace(refs.StringValue(user.Email)) != "" {
|
||||
if u, _ := p.GetUserByEmail(ctx, refs.StringValue(user.Email)); u != nil && u.ID != user.ID {
|
||||
return user, fmt.Errorf("user with given email already exists")
|
||||
}
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now().Unix()
|
||||
user.UpdatedAt = time.Now().Unix()
|
||||
user.Key = user.ID
|
||||
result := p.db.Clauses(
|
||||
clause.OnConflict{
|
||||
UpdateAll: true,
|
||||
Columns: []clause.Column{{Name: "email"}},
|
||||
}).Create(&user)
|
||||
result := p.db.Create(&user)
|
||||
|
||||
if result.Error != nil {
|
||||
return user, result.Error
|
||||
|
@ -113,7 +112,7 @@ func (p *provider) GetUserByEmail(ctx context.Context, email string) (*models.Us
|
|||
var user *models.User
|
||||
result := p.db.Where("email = ?", email).First(&user)
|
||||
if result.Error != nil {
|
||||
return user, result.Error
|
||||
return nil, result.Error
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
@ -123,7 +122,7 @@ func (p *provider) GetUserByID(ctx context.Context, id string) (*models.User, er
|
|||
var user *models.User
|
||||
result := p.db.Where("id = ?", id).First(&user)
|
||||
if result.Error != nil {
|
||||
return user, result.Error
|
||||
return nil, result.Error
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -53,13 +53,13 @@ const (
|
|||
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||
</tr>
|
||||
|
||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||
<p>Hey there 👋</p>
|
||||
<p>We have received request to verify email for <b>{{.org_name}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
|
||||
<p>We have received request to verify email for <b>{{.organization.name}}</b>. If this is correct, please confirm your email address by clicking the button below.</p> <br/>
|
||||
<a
|
||||
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Confirm Email</a>
|
||||
</td>
|
||||
|
|
|
@ -103,6 +103,7 @@ type ComplexityRoot struct {
|
|||
DisableLoginPage func(childComplexity int) int
|
||||
DisableMagicLinkLogin func(childComplexity int) int
|
||||
DisableMailOtpLogin func(childComplexity int) int
|
||||
DisableMobileBasicAuthentication func(childComplexity int) int
|
||||
DisableMultiFactorAuthentication func(childComplexity int) int
|
||||
DisablePlayground func(childComplexity int) int
|
||||
DisableRedisForEnv func(childComplexity int) int
|
||||
|
@ -753,6 +754,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Env.DisableMailOtpLogin(childComplexity), true
|
||||
|
||||
case "Env.DISABLE_MOBILE_BASIC_AUTHENTICATION":
|
||||
if e.complexity.Env.DisableMobileBasicAuthentication == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Env.DisableMobileBasicAuthentication(childComplexity), true
|
||||
|
||||
case "Env.DISABLE_MULTI_FACTOR_AUTHENTICATION":
|
||||
if e.complexity.Env.DisableMultiFactorAuthentication == nil {
|
||||
break
|
||||
|
@ -2543,6 +2551,7 @@ type Env {
|
|||
RESET_PASSWORD_URL: String
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||
DISABLE_LOGIN_PAGE: Boolean!
|
||||
DISABLE_SIGN_UP: Boolean!
|
||||
|
@ -2674,6 +2683,7 @@ input UpdateEnvInput {
|
|||
ADMIN_COOKIE_SECURE: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
DISABLE_LOGIN_PAGE: Boolean
|
||||
DISABLE_SIGN_UP: Boolean
|
||||
|
@ -2837,6 +2847,7 @@ input UpdateUserInput {
|
|||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
phone_number_verified: Boolean
|
||||
picture: String
|
||||
roles: [String]
|
||||
is_multi_factor_auth_enabled: Boolean
|
||||
|
@ -5849,6 +5860,50 @@ func (ec *executionContext) fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(ctx co
|
|||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.DisableMobileBasicAuthentication, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(bool)
|
||||
fc.Result = res
|
||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Env",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Env_DISABLE_MAGIC_LINK_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(ctx, field)
|
||||
if err != nil {
|
||||
|
@ -11694,6 +11749,8 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
|||
return ec.fieldContext_Env_DISABLE_EMAIL_VERIFICATION(ctx, field)
|
||||
case "DISABLE_BASIC_AUTHENTICATION":
|
||||
return ec.fieldContext_Env_DISABLE_BASIC_AUTHENTICATION(ctx, field)
|
||||
case "DISABLE_MOBILE_BASIC_AUTHENTICATION":
|
||||
return ec.fieldContext_Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx, field)
|
||||
case "DISABLE_MAGIC_LINK_LOGIN":
|
||||
return ec.fieldContext_Env_DISABLE_MAGIC_LINK_LOGIN(ctx, field)
|
||||
case "DISABLE_LOGIN_PAGE":
|
||||
|
@ -18288,7 +18345,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
|||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MOBILE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
|
@ -18493,6 +18550,15 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
|||
return it, err
|
||||
}
|
||||
it.DisableBasicAuthentication = data
|
||||
case "DISABLE_MOBILE_BASIC_AUTHENTICATION":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_MOBILE_BASIC_AUTHENTICATION"))
|
||||
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.DisableMobileBasicAuthentication = data
|
||||
case "DISABLE_MAGIC_LINK_LOGIN":
|
||||
var err error
|
||||
|
||||
|
@ -18985,7 +19051,7 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o
|
|||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"id", "email", "email_verified", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "picture", "roles", "is_multi_factor_auth_enabled", "app_data"}
|
||||
fieldsInOrder := [...]string{"id", "email", "email_verified", "given_name", "family_name", "middle_name", "nickname", "gender", "birthdate", "phone_number", "phone_number_verified", "picture", "roles", "is_multi_factor_auth_enabled", "app_data"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
|
@ -19082,6 +19148,15 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o
|
|||
return it, err
|
||||
}
|
||||
it.PhoneNumber = data
|
||||
case "phone_number_verified":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("phone_number_verified"))
|
||||
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.PhoneNumberVerified = data
|
||||
case "picture":
|
||||
var err error
|
||||
|
||||
|
@ -19672,6 +19747,11 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
|||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "DISABLE_MOBILE_BASIC_AUTHENTICATION":
|
||||
out.Values[i] = ec._Env_DISABLE_MOBILE_BASIC_AUTHENTICATION(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "DISABLE_MAGIC_LINK_LOGIN":
|
||||
out.Values[i] = ec._Env_DISABLE_MAGIC_LINK_LOGIN(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
|
|
|
@ -93,6 +93,7 @@ type Env struct {
|
|||
ResetPasswordURL *string `json:"RESET_PASSWORD_URL,omitempty"`
|
||||
DisableEmailVerification bool `json:"DISABLE_EMAIL_VERIFICATION"`
|
||||
DisableBasicAuthentication bool `json:"DISABLE_BASIC_AUTHENTICATION"`
|
||||
DisableMobileBasicAuthentication bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION"`
|
||||
DisableMagicLinkLogin bool `json:"DISABLE_MAGIC_LINK_LOGIN"`
|
||||
DisableLoginPage bool `json:"DISABLE_LOGIN_PAGE"`
|
||||
DisableSignUp bool `json:"DISABLE_SIGN_UP"`
|
||||
|
@ -373,6 +374,7 @@ type UpdateEnvInput struct {
|
|||
AdminCookieSecure *bool `json:"ADMIN_COOKIE_SECURE,omitempty"`
|
||||
DisableEmailVerification *bool `json:"DISABLE_EMAIL_VERIFICATION,omitempty"`
|
||||
DisableBasicAuthentication *bool `json:"DISABLE_BASIC_AUTHENTICATION,omitempty"`
|
||||
DisableMobileBasicAuthentication *bool `json:"DISABLE_MOBILE_BASIC_AUTHENTICATION,omitempty"`
|
||||
DisableMagicLinkLogin *bool `json:"DISABLE_MAGIC_LINK_LOGIN,omitempty"`
|
||||
DisableLoginPage *bool `json:"DISABLE_LOGIN_PAGE,omitempty"`
|
||||
DisableSignUp *bool `json:"DISABLE_SIGN_UP,omitempty"`
|
||||
|
@ -440,6 +442,7 @@ type UpdateUserInput struct {
|
|||
Gender *string `json:"gender,omitempty"`
|
||||
Birthdate *string `json:"birthdate,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
PhoneNumberVerified *bool `json:"phone_number_verified,omitempty"`
|
||||
Picture *string `json:"picture,omitempty"`
|
||||
Roles []*string `json:"roles,omitempty"`
|
||||
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled,omitempty"`
|
||||
|
|
|
@ -158,6 +158,7 @@ type Env {
|
|||
RESET_PASSWORD_URL: String
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean!
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||
DISABLE_LOGIN_PAGE: Boolean!
|
||||
DISABLE_SIGN_UP: Boolean!
|
||||
|
@ -289,6 +290,7 @@ input UpdateEnvInput {
|
|||
ADMIN_COOKIE_SECURE: Boolean
|
||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MOBILE_BASIC_AUTHENTICATION: Boolean
|
||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||
DISABLE_LOGIN_PAGE: Boolean
|
||||
DISABLE_SIGN_UP: Boolean
|
||||
|
@ -452,6 +454,7 @@ input UpdateUserInput {
|
|||
gender: String
|
||||
birthdate: String
|
||||
phone_number: String
|
||||
phone_number_verified: Boolean
|
||||
picture: String
|
||||
roles: [String]
|
||||
is_multi_factor_auth_enabled: Boolean
|
||||
|
|
|
@ -617,7 +617,7 @@ func processAppleUserInfo(ctx context.Context, code string) (*models.User, error
|
|||
}
|
||||
}
|
||||
|
||||
return user, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func processDiscordUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||
|
|
|
@ -24,9 +24,13 @@ func RevokeRefreshTokenHandler() gin.HandlerFunc {
|
|||
})
|
||||
return
|
||||
}
|
||||
// get client ID
|
||||
clientID := strings.TrimSpace(reqBody["client_id"]) // kept for backward compatibility // else we expect to be present as header
|
||||
if clientID == "" {
|
||||
clientID = gc.Request.Header.Get("x-authorizer-client-id")
|
||||
}
|
||||
// get fingerprint hash
|
||||
refreshToken := strings.TrimSpace(reqBody["refresh_token"])
|
||||
clientID := strings.TrimSpace(reqBody["client_id"])
|
||||
|
||||
if clientID == "" {
|
||||
log.Debug("Client ID is empty")
|
||||
|
|
29
server/middlewares/client_check.go
Normal file
29
server/middlewares/client_check.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
)
|
||||
|
||||
// ClientCheckMiddleware is a middleware to verify the client ID
|
||||
// Note: client ID is passed in the header
|
||||
func ClientCheckMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
clientID := c.Request.Header.Get("X-Authorizer-Client-ID")
|
||||
if client, _ := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID); clientID != "" && client != "" && client != clientID {
|
||||
log.Debug("Client ID is invalid: ", clientID)
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "invalid_client_id",
|
||||
"error_description": "The client id is invalid",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ func CORSMiddleware() gin.HandlerFunc {
|
|||
}
|
||||
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, X-authorizer-url")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, X-authorizer-url, X-Forwarded-Proto, X-authorizer-client-id")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
|
|
|
@ -205,6 +205,7 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
|||
// bool vars
|
||||
res.DisableEmailVerification = store[constants.EnvKeyDisableEmailVerification].(bool)
|
||||
res.DisableBasicAuthentication = store[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||
res.DisableMobileBasicAuthentication = store[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||
res.DisableMagicLinkLogin = store[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||
res.DisableLoginPage = store[constants.EnvKeyDisableLoginPage].(bool)
|
||||
res.DisableSignUp = store[constants.EnvKeyDisableSignUp].(bool)
|
||||
|
|
|
@ -83,6 +83,39 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
log.Debug("User access is revoked")
|
||||
return res, fmt.Errorf(`user access has been revoked`)
|
||||
}
|
||||
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
if err != nil || !isEmailServiceEnabled {
|
||||
log.Debug("Email service not enabled: ", err)
|
||||
}
|
||||
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled)
|
||||
if err != nil || !isSMSServiceEnabled {
|
||||
log.Debug("SMS service not enabled: ", err)
|
||||
}
|
||||
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||
otp := utils.GenerateOTP()
|
||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return otpData, nil
|
||||
}
|
||||
setOTPMFaSession := func(expiresAt int64) error {
|
||||
mfaSession := uuid.NewString()
|
||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to add mfasession: ", err)
|
||||
return err
|
||||
}
|
||||
cookie.SetMfaSession(gc, mfaSession)
|
||||
return nil
|
||||
}
|
||||
if isEmailLogin {
|
||||
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodBasicAuth) {
|
||||
log.Debug("User signup method is not basic auth")
|
||||
|
@ -90,8 +123,38 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
}
|
||||
|
||||
if user.EmailVerifiedAt == nil {
|
||||
log.Debug("User email is not verified")
|
||||
return res, fmt.Errorf(`email not verified`)
|
||||
// Check if email service is enabled
|
||||
// Send email verification via otp
|
||||
if !isEmailServiceEnabled {
|
||||
log.Debug("User email is not verified and email service is not enabled")
|
||||
return res, fmt.Errorf(`email not verified`)
|
||||
} else {
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otpData, err := generateOTP(expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"otp": otpData.Otp,
|
||||
}); err != nil {
|
||||
log.Debug("Failed to send otp email: ", err)
|
||||
}
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||
}()
|
||||
return &model.AuthResponse{
|
||||
Message: "Please check email inbox for the OTP",
|
||||
ShouldShowEmailOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
|
||||
|
@ -100,8 +163,34 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
}
|
||||
|
||||
if user.PhoneNumberVerifiedAt == nil {
|
||||
log.Debug("User phone number is not verified")
|
||||
return res, fmt.Errorf(`phone number is not verified`)
|
||||
if !isSMSServiceEnabled {
|
||||
log.Debug("User phone number is not verified")
|
||||
return res, fmt.Errorf(`phone number is not verified and sms service is not enabled`)
|
||||
} else {
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otpData, err := generateOTP(expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(otpData.Otp)
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||
log.Debug("Failed to send sms: ", err)
|
||||
}
|
||||
}()
|
||||
return &model.AuthResponse{
|
||||
Message: "Please check text message for the OTP",
|
||||
ShouldShowMobileOtpScreen: refs.NewBoolRef(isMobileLogin),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
|
||||
|
@ -129,14 +218,6 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
if params.Scope != nil && len(scope) > 0 {
|
||||
scope = params.Scope
|
||||
}
|
||||
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
if err != nil || !isEmailServiceEnabled {
|
||||
log.Debug("Email service not enabled: ", err)
|
||||
}
|
||||
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsSMSServiceEnabled)
|
||||
if err != nil || !isSMSServiceEnabled {
|
||||
log.Debug("SMS service not enabled: ", err)
|
||||
}
|
||||
|
||||
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||
if err != nil || !isMFADisabled {
|
||||
|
@ -157,44 +238,20 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
if err != nil || !isSMSOTPDisabled {
|
||||
log.Debug("sms OTP service not enabled: ", err)
|
||||
}
|
||||
setOTPMFaSession := func(expiresAt int64) error {
|
||||
mfaSession := uuid.NewString()
|
||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to add mfasession: ", err)
|
||||
return err
|
||||
}
|
||||
cookie.SetMfaSession(gc, mfaSession)
|
||||
return nil
|
||||
}
|
||||
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||
otp := utils.GenerateOTP()
|
||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return otpData, nil
|
||||
}
|
||||
|
||||
// If multi factor authentication is enabled and is email based login and email otp is enabled
|
||||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isMailOTPDisabled && isEmailServiceEnabled && isEmailLogin {
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otpData, err := generateOTP(expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return
|
||||
}
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
|
@ -214,15 +271,15 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
|||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMFADisabled && !isSMSOTPDisabled && isSMSServiceEnabled && isMobileLogin {
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otpData, err := generateOTP(expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return
|
||||
}
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(otpData.Otp)
|
||||
|
|
|
@ -7,12 +7,14 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
emailHelper "github.com/authorizerdev/authorizer/server/email"
|
||||
mailService "github.com/authorizerdev/authorizer/server/email"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/refs"
|
||||
|
@ -32,44 +34,42 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
|||
log.Debug("Email or phone number is required")
|
||||
return nil, errors.New("email or phone number is required")
|
||||
}
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get GinContext: ", err)
|
||||
return nil, err
|
||||
}
|
||||
var user *models.User
|
||||
var err error
|
||||
var isEmailServiceEnabled, isSMSServiceEnabled bool
|
||||
if email != "" {
|
||||
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
isEmailServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
if err != nil || !isEmailServiceEnabled {
|
||||
log.Debug("Email service not enabled: ", err)
|
||||
return nil, errors.New("email service not enabled")
|
||||
}
|
||||
user, err = db.Provider.GetUserByEmail(ctx, email)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user by email: ", err)
|
||||
return nil, fmt.Errorf(`user with this email/phone not found`)
|
||||
}
|
||||
} else {
|
||||
isSMSServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
isSMSServiceEnabled, err = memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||
if err != nil || !isSMSServiceEnabled {
|
||||
log.Debug("Email service not enabled: ", err)
|
||||
return nil, errors.New("email service not enabled")
|
||||
}
|
||||
user, err = db.Provider.GetUserByPhoneNumber(ctx, phoneNumber)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user by phone: ", err)
|
||||
return nil, fmt.Errorf(`user with this email/phone not found`)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user by email: ", err)
|
||||
return nil, fmt.Errorf(`user with this email/phone not found`)
|
||||
}
|
||||
|
||||
if user.RevokedTimestamp != nil {
|
||||
log.Debug("User access is revoked")
|
||||
return nil, fmt.Errorf(`user access has been revoked`)
|
||||
}
|
||||
|
||||
if email != "" && user.EmailVerifiedAt == nil {
|
||||
log.Debug("User email is not verified")
|
||||
return nil, fmt.Errorf(`email not verified`)
|
||||
}
|
||||
|
||||
if phoneNumber != "" && user.PhoneNumberVerifiedAt == nil {
|
||||
log.Debug("User phone number is not verified")
|
||||
return nil, fmt.Errorf(`phone number not verified`)
|
||||
}
|
||||
|
||||
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
||||
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) && user.EmailVerifiedAt != nil && user.PhoneNumberVerifiedAt != nil {
|
||||
log.Debug("User multi factor authentication is not enabled")
|
||||
return nil, fmt.Errorf(`multi factor authentication not enabled`)
|
||||
}
|
||||
|
@ -97,30 +97,63 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
|||
Message: "Failed to get for given email",
|
||||
}, errors.New("failed to get otp for given email")
|
||||
}
|
||||
|
||||
otp := utils.GenerateOTP()
|
||||
if _, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
Otp: otp,
|
||||
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||
}); err != nil {
|
||||
log.Debug("Error upserting otp: ", err)
|
||||
// If multi factor authentication is enabled and we need to generate OTP for mail / sms based MFA
|
||||
generateOTP := func(expiresAt int64) (*models.OTP, error) {
|
||||
otp := utils.GenerateOTP()
|
||||
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Email: refs.StringValue(user.Email),
|
||||
PhoneNumber: refs.StringValue(user.PhoneNumber),
|
||||
Otp: otp,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Failed to add otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return otpData, nil
|
||||
}
|
||||
setOTPMFaSession := func(expiresAt int64) error {
|
||||
mfaSession := uuid.NewString()
|
||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to add mfasession: ", err)
|
||||
return err
|
||||
}
|
||||
cookie.SetMfaSession(gc, mfaSession)
|
||||
return nil
|
||||
}
|
||||
expiresAt := time.Now().Add(1 * time.Minute).Unix()
|
||||
otpData, err = generateOTP(expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to generate otp: ", err)
|
||||
return nil, err
|
||||
}
|
||||
if err := setOTPMFaSession(expiresAt); err != nil {
|
||||
log.Debug("Failed to set mfa session: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if email != "" {
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
go emailHelper.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"otp": otp,
|
||||
})
|
||||
go func() {
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
if err := mailService.SendEmail([]string{email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||
"user": user.ToMap(),
|
||||
"organization": utils.GetOrganization(),
|
||||
"otp": otpData.Otp,
|
||||
}); err != nil {
|
||||
log.Debug("Failed to send otp email: ", err)
|
||||
}
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||
}()
|
||||
} else {
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(otp)
|
||||
// exec it as go routine so that we can reduce the api latency
|
||||
go smsproviders.SendSMS(phoneNumber, smsBody.String())
|
||||
go func() {
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(otpData.Otp)
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||
if err := smsproviders.SendSMS(phoneNumber, smsBody.String()); err != nil {
|
||||
log.Debug("Failed to send sms: ", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
log.Info("OTP has been resent")
|
||||
return &model.Response{
|
||||
|
|
|
@ -290,25 +290,26 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
|||
} else if !disablePhoneVerification && isSMSServiceEnabled && isMobileSignup {
|
||||
duration, _ := time.ParseDuration("10m")
|
||||
smsCode := utils.GenerateOTP()
|
||||
|
||||
smsBody := strings.Builder{}
|
||||
smsBody.WriteString("Your verification code is: ")
|
||||
smsBody.WriteString(smsCode)
|
||||
|
||||
// TODO: For those who enabled the webhook to call their sms vendor separately - sending the otp to their api
|
||||
if err != nil {
|
||||
log.Debug("error while upserting user: ", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
expiresAt := time.Now().Add(duration).Unix()
|
||||
_, err = db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
PhoneNumber: phoneNumber,
|
||||
Otp: smsCode,
|
||||
ExpiresAt: time.Now().Add(duration).Unix(),
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("error while upserting OTP: ", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
mfaSession := uuid.NewString()
|
||||
err = memorystore.Provider.SetMfaSession(user.ID, mfaSession, expiresAt)
|
||||
if err != nil {
|
||||
log.Debug("Failed to add mfasession: ", err)
|
||||
return nil, err
|
||||
}
|
||||
cookie.SetMfaSession(gc, mfaSession)
|
||||
go func() {
|
||||
smsproviders.SendSMS(phoneNumber, smsBody.String())
|
||||
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||
|
|
|
@ -48,7 +48,18 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||
"user_id": params.ID,
|
||||
})
|
||||
|
||||
if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.Roles == nil && params.IsMultiFactorAuthEnabled == nil && params.AppData == nil {
|
||||
if params.GivenName == nil &&
|
||||
params.FamilyName == nil &&
|
||||
params.Picture == nil &&
|
||||
params.MiddleName == nil &&
|
||||
params.Nickname == nil &&
|
||||
params.Email == nil &&
|
||||
params.Birthdate == nil &&
|
||||
params.Gender == nil &&
|
||||
params.PhoneNumber == nil &&
|
||||
params.Roles == nil &&
|
||||
params.IsMultiFactorAuthEnabled == nil &&
|
||||
params.AppData == nil {
|
||||
log.Debug("No params to update")
|
||||
return res, fmt.Errorf("please enter atleast one param to update")
|
||||
}
|
||||
|
@ -142,6 +153,15 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||
user.EmailVerifiedAt = nil
|
||||
}
|
||||
}
|
||||
if params.PhoneNumberVerified != nil {
|
||||
if *params.PhoneNumberVerified {
|
||||
now := time.Now().Unix()
|
||||
user.PhoneNumberVerifiedAt = &now
|
||||
} else {
|
||||
user.PhoneNumberVerifiedAt = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if params.Email != nil && refs.StringValue(user.Email) != refs.StringValue(params.Email) {
|
||||
// check if valid email
|
||||
|
@ -197,6 +217,24 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||
|
||||
}
|
||||
|
||||
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||
phone := strings.TrimSpace(refs.StringValue(params.PhoneNumber))
|
||||
if len(phone) < 10 || len(phone) > 15 {
|
||||
log.Debug("Invalid phone number: ", *params.PhoneNumber)
|
||||
return res, fmt.Errorf("invalid phone number")
|
||||
}
|
||||
// check if user with new phone number exists
|
||||
_, err = db.Provider.GetUserByPhoneNumber(ctx, phone)
|
||||
// err = nil means user exists
|
||||
if err == nil {
|
||||
log.Debug("User with phone number already exists: ", phone)
|
||||
return res, fmt.Errorf("user with this phone number already exists")
|
||||
}
|
||||
go memorystore.Provider.DeleteAllUserSessions(user.ID)
|
||||
user.PhoneNumber = &phone
|
||||
user.PhoneNumberVerifiedAt = nil
|
||||
}
|
||||
|
||||
rolesToSave := ""
|
||||
if params.Roles != nil && len(params.Roles) > 0 {
|
||||
currentRoles := strings.Split(user.Roles, ",")
|
||||
|
@ -237,7 +275,6 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
|||
if rolesToSave != "" {
|
||||
user.Roles = rolesToSave
|
||||
}
|
||||
|
||||
user, err = db.Provider.UpdateUser(ctx, user)
|
||||
if err != nil {
|
||||
log.Debug("Failed to update user: ", err)
|
||||
|
|
|
@ -16,6 +16,7 @@ func InitRouter(log *logrus.Logger) *gin.Engine {
|
|||
router.Use(middlewares.Logger(log), gin.Recovery())
|
||||
router.Use(middlewares.GinContextToContextMiddleware())
|
||||
router.Use(middlewares.CORSMiddleware())
|
||||
router.Use(middlewares.ClientCheckMiddleware())
|
||||
|
||||
router.GET("/", handlers.RootHandler())
|
||||
router.GET("/health", handlers.HealthHandler())
|
||||
|
|
|
@ -28,9 +28,11 @@ func loginTests(t *testing.T, s TestSetup) {
|
|||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
|
||||
assert.NotNil(t, err, "should fail because email is not verified")
|
||||
assert.Nil(t, res)
|
||||
// access token should be empty as email is not verified
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.Nil(t, res.AccessToken)
|
||||
assert.NotEmpty(t, res.Message)
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, verificationRequest)
|
||||
|
|
|
@ -33,8 +33,12 @@ func mobileLoginTests(t *testing.T, s TestSetup) {
|
|||
PhoneNumber: refs.NewStringRef(phoneNumber),
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
assert.NotNil(t, err, "should fail because phone is not verified")
|
||||
assert.Nil(t, res)
|
||||
// access token should be empty as email is not verified
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.Nil(t, res.AccessToken)
|
||||
assert.NotEmpty(t, res.Message)
|
||||
assert.True(t, *res.ShouldShowMobileOtpScreen)
|
||||
smsRequest, err := db.Provider.GetOTPByPhoneNumber(ctx, phoneNumber)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, smsRequest.Otp)
|
||||
|
|
|
@ -35,8 +35,11 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
|||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, loginRes)
|
||||
// access token should be empty as email is not verified
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, loginRes)
|
||||
assert.Nil(t, loginRes.AccessToken)
|
||||
assert.NotEmpty(t, loginRes.Message)
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, email, verificationRequest.Email)
|
||||
|
@ -57,13 +60,6 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
|||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMailOTPLogin, false)
|
||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableTOTPLogin, true)
|
||||
|
||||
// Resend otp should return error as no initial opt is being sent
|
||||
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
||||
Email: refs.NewStringRef(email),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, resendOtpRes)
|
||||
|
||||
// Login should not return error but access token should be empty as otp should have been sent
|
||||
loginRes, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||
Email: refs.NewStringRef(email),
|
||||
|
@ -79,7 +75,7 @@ func resendOTPTest(t *testing.T, s TestSetup) {
|
|||
assert.NotEmpty(t, otp.Otp)
|
||||
|
||||
// resend otp
|
||||
resendOtpRes, err = resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
||||
resendOtpRes, err := resolvers.ResendOTPResolver(ctx, model.ResendOTPRequest{
|
||||
Email: refs.NewStringRef(email),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -42,8 +42,11 @@ func totpLoginTest(t *testing.T, s TestSetup) {
|
|||
Email: &email,
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, loginRes)
|
||||
// access token should be empty as email is not verified
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, loginRes)
|
||||
assert.Nil(t, loginRes.AccessToken)
|
||||
assert.NotEmpty(t, loginRes.Message)
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, email, verificationRequest.Email)
|
||||
|
|
|
@ -47,8 +47,10 @@ func verifyOTPTest(t *testing.T, s TestSetup) {
|
|||
Email: refs.NewStringRef(email),
|
||||
Password: s.TestInfo.Password,
|
||||
})
|
||||
assert.NotNil(t, err, "email is not verified")
|
||||
assert.Nil(t, loginRes)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, loginRes)
|
||||
assert.Nil(t, loginRes.AccessToken)
|
||||
assert.NotEmpty(t, loginRes.Message)
|
||||
|
||||
// Verify the email
|
||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
|
||||
|
|
Loading…
Reference in New Issue
Block a user