- {/*
- {wallpaperData?.author ? wallpaperData.author : null}
-
*/}
+ />
+
+
+
+

+
+
+
+ {React.createElement(
+ keyToComponents[activeKey] ?? keyToComponents["selector"],
+ {
+ setActiveKey: setActiveKey,
+ },
+ )}
+
)
}
+
+export default AuthPage
diff --git a/packages/app/src/pages/auth/index.mobile.less b/packages/app/src/pages/auth/index.mobile.less
index b05a5d18..ea485231 100755
--- a/packages/app/src/pages/auth/index.mobile.less
+++ b/packages/app/src/pages/auth/index.mobile.less
@@ -1,22 +1,89 @@
-.loginPage {
- position: relative;
+.login-page {
+ position: relative;
- width: 100%;
- height: 100vh;
- height: 100dvh;
+ display: flex;
+ flex-direction: column;
- .wallpaper {
- position: absolute;
+ align-items: center;
+ justify-content: center;
- top: 0;
- left: 0;
+ width: 100%;
+ height: 100vh;
+ height: 100dvh;
- width: 100%;
- height: 100vh;
- height: 100dvh;
+ .wallpaper {
+ position: fixed;
- background-position: center;
- background-size: cover;
- background-repeat: no-repeat;
- }
-}
\ No newline at end of file
+ top: 0;
+ left: 0;
+
+ z-index: -1;
+
+ width: 100%;
+ height: 100vh;
+ height: 100dvh;
+
+ background-position: center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ }
+
+ .login-page-card {
+ position: relative;
+
+ display: flex;
+ flex-direction: column;
+
+ width: 95%;
+ padding: 15px;
+
+ background-color: var(--background-color-primary);
+
+ border-radius: 24px;
+
+ gap: 30px;
+
+ &__header {
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+
+ gap: 10px;
+
+ &__logo {
+ width: 40px;
+ height: 40px;
+ }
+ }
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+
+ .ant-btn {
+ height: fit-content;
+ padding: 7px 15px;
+ font-size: 0.8rem;
+ }
+
+ .actions {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ gap: 15px;
+ }
+
+ .register_form {
+ position: unset;
+
+ .register_form_actions {
+ top: 0;
+ bottom: unset;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/app/src/pages/lyrics/components/text/index.jsx b/packages/app/src/pages/lyrics/components/text/index.jsx
index 3fe85416..a2b3e3fd 100644
--- a/packages/app/src/pages/lyrics/components/text/index.jsx
+++ b/packages/app/src/pages/lyrics/components/text/index.jsx
@@ -104,6 +104,8 @@ const LyricsText = React.forwardRef((props, textRef) => {
React.useEffect(() => {
setVisible(false)
setCurrentLineIndex(0)
+ // set scroll top to 0
+ textRef.current.scrollTop = 0
}, [playerState.track_manifest])
React.useEffect(() => {
diff --git a/packages/server/services/auth/auth.service.js b/packages/server/services/auth/auth.service.js
index 1cb3f8aa..b0e008f8 100644
--- a/packages/server/services/auth/auth.service.js
+++ b/packages/server/services/auth/auth.service.js
@@ -35,7 +35,6 @@ export default class API extends Server {
onExit() {
this.queuesManager.cleanUp()
- console.log("Jijija")
}
}
diff --git a/packages/server/services/auth/classes/account/methods/create.js b/packages/server/services/auth/classes/account/methods/create.js
index d64c280a..63478c75 100644
--- a/packages/server/services/auth/classes/account/methods/create.js
+++ b/packages/server/services/auth/classes/account/methods/create.js
@@ -1,60 +1,84 @@
import bcrypt from "bcrypt"
import { User } from "@db_models"
-import requiredFields from "@shared-utils/requiredFields"
-
import Account from "@classes/account"
+import requiredFields from "@shared-utils/requiredFields"
+import verifyTurnstileToken from "@utils/verifyTurnstileToken"
+
export default async (payload) => {
- requiredFields(["username", "password", "email"], payload)
+ requiredFields(["username", "password", "email"], payload)
- let { username, password, email, public_name, roles, avatar, accept_tos } = payload
+ let {
+ username,
+ password,
+ email,
+ public_name,
+ roles,
+ avatar,
+ accept_tos,
+ captcha,
+ } = payload
- if (ToBoolean(accept_tos) !== true) {
- throw new OperationError(400, "You must accept the terms of service in order to create an account.")
- }
+ if (ToBoolean(accept_tos) !== true) {
+ throw new OperationError(
+ 400,
+ "You must accept the terms of service in order to create an account.",
+ )
+ }
- await Account.usernameMeetPolicy(username)
+ if (!captcha) {
+ throw new OperationError(400, "Captcha token is required")
+ }
- // check if username is already taken
- const existentUser = await User
- .findOne({ username: username })
+ const turnstileResponse = await verifyTurnstileToken(captcha)
- if (existentUser) {
- throw new OperationError(400, "User already exists")
- }
+ if (turnstileResponse.success !== true) {
+ throw new OperationError(400, "Invalid captcha token")
+ }
- // check if the email is already in use
- const existentEmail = await User
- .findOne({ email: email })
- .select("+email")
+ await Account.usernameMeetPolicy(username)
- if (existentEmail) {
- throw new OperationError(400, "Email already in use")
- }
+ // check if username is already taken
+ const existentUser = await User.findOne({ username: username })
- await Account.passwordMeetPolicy(password)
+ if (existentUser) {
+ throw new OperationError(400, "User already exists")
+ }
- // hash the password
- const hash = bcrypt.hashSync(password, parseInt(process.env.BCRYPT_ROUNDS ?? 3))
+ // check if the email is already in use
+ const existentEmail = await User.findOne({ email: email }).select("+email")
- let user = new User({
- username: username,
- password: hash,
- email: email,
- public_name: public_name,
- avatar: avatar ?? `https://api.dicebear.com/7.x/thumbs/svg?seed=${username}`,
- roles: roles,
- created_at: new Date().getTime(),
- accept_tos: accept_tos,
- activated: false,
- })
+ if (existentEmail) {
+ throw new OperationError(400, "Email already in use")
+ }
- await user.save()
+ await Account.passwordMeetPolicy(password)
- await Account.sendActivationCode(user._id.toString())
+ // hash the password
+ const hash = bcrypt.hashSync(
+ password,
+ parseInt(process.env.BCRYPT_ROUNDS ?? 3),
+ )
- return {
- activation_required: true,
- user: user,
- }
-}
\ No newline at end of file
+ let user = new User({
+ username: username,
+ password: hash,
+ email: email,
+ public_name: public_name,
+ avatar:
+ avatar ?? `https://api.dicebear.com/7.x/thumbs/svg?seed=${username}`,
+ roles: roles,
+ created_at: new Date().getTime(),
+ accept_tos: accept_tos,
+ activated: false,
+ })
+
+ await user.save()
+
+ await Account.sendActivationCode(user._id.toString())
+
+ return {
+ activation_required: true,
+ user: user,
+ }
+}
diff --git a/packages/server/services/auth/utils/verifyTurnstileToken.js b/packages/server/services/auth/utils/verifyTurnstileToken.js
new file mode 100644
index 00000000..693c52c1
--- /dev/null
+++ b/packages/server/services/auth/utils/verifyTurnstileToken.js
@@ -0,0 +1,26 @@
+import axios from "axios"
+
+export default async (token) => {
+ const secret = process.env.TURNSTILE_SECRET
+
+ if (!secret) {
+ throw new Error("Turnstile secret is not set")
+ }
+
+ let response = await axios({
+ url: "https://challenges.cloudflare.com/turnstile/v0/siteverify",
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ data: {
+ secret: secret,
+ response: token,
+ },
+ }).catch((err) => {
+ console.error(err.response.data)
+ throw new Error("Turnstile verification failed")
+ })
+
+ return response.data
+}