Refactor login components and adjust login API routes (#1678)

* Refactor login components and adjust API routes

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Adjust API /me response and redux state

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Fix moved function

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Update cypress tests

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Adjust mock response

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Integrate new common fields and hook into profile page

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Remove openid

Signed-off-by: Erik Michelson <github@erik.michelson.eu>

* Fix config mock

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>

Co-authored-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Erik Michelson 2021-12-11 01:32:38 +01:00 committed by GitHub
parent fe640268c5
commit eab189c3c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 911 additions and 507 deletions

View file

@ -3,62 +3,31 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { RegisterError } from '../../components/register-page/register-page'
import { defaultFetchConfig, expectResponseCode, getApiUrl } from '../utils'
export const INTERACTIVE_LOGIN_METHODS = ['internal', 'ldap', 'openid']
export const INTERACTIVE_LOGIN_METHODS = ['local', 'ldap']
export const doInternalLogin = async (username: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/internal', {
export enum AuthError {
INVALID_CREDENTIALS = 'invalidCredentials',
LOGIN_DISABLED = 'loginDisabled',
OPENID_ERROR = 'openIdError',
OTHER = 'other'
}
export enum RegisterError {
USERNAME_EXISTING = 'usernameExisting',
REGISTRATION_DISABLED = 'registrationDisabled',
OTHER = 'other'
}
/**
* Requests to logout the current user.
* @throws Error if logout is not possible.
*/
export const doLogout = async (): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/logout', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username: username,
password: password
})
})
expectResponseCode(response)
}
export const doInternalRegister = async (username: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/register', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username: username,
password: password
})
})
if (response.status === 409) {
throw new Error(RegisterError.USERNAME_EXISTING)
}
expectResponseCode(response)
}
export const doLdapLogin = async (username: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/ldap', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username: username,
password: password
})
})
expectResponseCode(response)
}
export const doOpenIdLogin = async (openId: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/openid', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
openId: openId
})
method: 'DELETE'
})
expectResponseCode(response)

25
src/api/auth/ldap.ts Normal file
View file

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defaultFetchConfig, expectResponseCode, getApiUrl } from '../utils'
/**
* Requests to login a user via LDAP credentials.
* @param username The username with which to try the login.
* @param password The password of the user.
*/
export const doLdapLogin = async (username: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/ldap', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username: username,
password: password
})
})
expectResponseCode(response)
}

94
src/api/auth/local.ts Normal file
View file

@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defaultFetchConfig, expectResponseCode, getApiUrl } from '../utils'
import { AuthError, RegisterError } from './index'
/**
* Requests to do a local login with a provided username and password.
* @param username The username for which the login should be tried.
* @param password The password which should be used to login.
* @throws {AuthError.INVALID_CREDENTIALS} when the username or password is wrong.
* @throws {AuthError.LOGIN_DISABLED} when the local login is disabled on the backend.
*/
export const doLocalLogin = async (username: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/local/login', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username,
password
})
})
if (response.status === 400) {
throw new Error(AuthError.LOGIN_DISABLED)
}
if (response.status === 401) {
throw new Error(AuthError.INVALID_CREDENTIALS)
}
expectResponseCode(response, 201)
}
/**
* Requests to register a new local user in the backend.
* @param username The username of the new user.
* @param displayName The display name of the new user.
* @param password The password of the new user.
* @throws {RegisterError.USERNAME_EXISTING} when there is already an existing user with the same user name.
* @throws {RegisterError.REGISTRATION_DISABLED} when the registration of local users has been disabled on the backend.
*/
export const doLocalRegister = async (username: string, displayName: string, password: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/local', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
username,
displayName,
password
})
})
if (response.status === 409) {
throw new Error(RegisterError.USERNAME_EXISTING)
}
if (response.status === 400) {
throw new Error(RegisterError.REGISTRATION_DISABLED)
}
expectResponseCode(response)
}
/**
* Requests to update the user's current password to a new one.
* @param currentPassword The current password of the user for confirmation.
* @param newPassword The new password of the user.
* @throws {AuthError.INVALID_CREDENTIALS} when the current password is wrong.
* @throws {AuthError.LOGIN_DISABLED} when local login is disabled on the backend.
*/
export const doLocalPasswordChange = async (currentPassword: string, newPassword: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'auth/local', {
...defaultFetchConfig,
method: 'PUT',
body: JSON.stringify({
currentPassword,
newPassword
})
})
if (response.status === 401) {
throw new Error(AuthError.INVALID_CREDENTIALS)
}
if (response.status === 400) {
throw new Error(AuthError.LOGIN_DISABLED)
}
expectResponseCode(response)
}

View file

@ -46,8 +46,7 @@ export interface AuthProvidersState {
google: boolean
saml: boolean
oauth2: boolean
internal: boolean
openid: boolean
local: boolean
}
export interface CustomAuthNames {

View file

@ -4,16 +4,21 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { UserResponse } from '../users/types'
import type { UserInfoDto } from '../users/types'
import { defaultFetchConfig, expectResponseCode, getApiUrl } from '../utils'
import { isMockMode } from '../../utils/test-modes'
export const getMe = async (): Promise<UserResponse> => {
/**
* Returns metadata about the currently signed-in user from the API.
* @throws Error when the user is not signed-in.
* @return The user metadata.
*/
export const getMe = async (): Promise<UserInfoDto> => {
const response = await fetch(getApiUrl() + `me${isMockMode() ? '-get' : ''}`, {
...defaultFetchConfig
})
expectResponseCode(response)
return (await response.json()) as UserResponse
return (await response.json()) as UserInfoDto
}
export const updateDisplayName = async (displayName: string): Promise<void> => {
@ -28,19 +33,6 @@ export const updateDisplayName = async (displayName: string): Promise<void> => {
expectResponseCode(response)
}
export const changePassword = async (oldPassword: string, newPassword: string): Promise<void> => {
const response = await fetch(getApiUrl() + 'me/password', {
...defaultFetchConfig,
method: 'POST',
body: JSON.stringify({
oldPassword,
newPassword
})
})
expectResponseCode(response)
}
export const deleteUser = async (): Promise<void> => {
const response = await fetch(getApiUrl() + 'me', {
...defaultFetchConfig,

View file

@ -14,7 +14,7 @@ export interface UserResponse {
}
export interface UserInfoDto {
userName: string
username: string
displayName: string
photo: string
email: string