Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
c069b3b1
"backend/internal/vscode:/vscode.git/clone" did not exist on "f7e95969522e521ee4fa08eff0e792fbee0d401e"
Commit
c069b3b1
authored
Mar 09, 2026
by
Elysia
Browse files
fix issue #836 linux.do注册无需邀请码
parent
ee7d0610
Changes
7
Hide whitespace changes
Inline
Side-by-side
backend/internal/handler/auth_linuxdo_oauth.go
View file @
c069b3b1
...
...
@@ -211,8 +211,22 @@ func (h *AuthHandler) LinuxDoOAuthCallback(c *gin.Context) {
email
=
linuxDoSyntheticEmail
(
subject
)
}
tokenPair
,
_
,
err
:=
h
.
authService
.
LoginOrRegisterOAuthWithTokenPair
(
c
.
Request
.
Context
(),
email
,
username
)
// 传入空邀请码;如果需要邀请码,服务层返回 ErrOAuthInvitationRequired
tokenPair
,
_
,
err
:=
h
.
authService
.
LoginOrRegisterOAuthWithTokenPair
(
c
.
Request
.
Context
(),
email
,
username
,
""
)
if
err
!=
nil
{
if
errors
.
Is
(
err
,
service
.
ErrOAuthInvitationRequired
)
{
pendingToken
,
tokenErr
:=
h
.
authService
.
CreatePendingOAuthToken
(
email
,
username
)
if
tokenErr
!=
nil
{
redirectOAuthError
(
c
,
frontendCallback
,
"login_failed"
,
"service_error"
,
""
)
return
}
fragment
:=
url
.
Values
{}
fragment
.
Set
(
"error"
,
"invitation_required"
)
fragment
.
Set
(
"pending_oauth_token"
,
pendingToken
)
fragment
.
Set
(
"redirect"
,
redirectTo
)
redirectWithFragment
(
c
,
frontendCallback
,
fragment
)
return
}
// 避免把内部细节泄露给客户端;给前端保留结构化原因与提示信息即可。
redirectOAuthError
(
c
,
frontendCallback
,
"login_failed"
,
infraerrors
.
Reason
(
err
),
infraerrors
.
Message
(
err
))
return
...
...
@@ -227,6 +241,45 @@ func (h *AuthHandler) LinuxDoOAuthCallback(c *gin.Context) {
redirectWithFragment
(
c
,
frontendCallback
,
fragment
)
}
type
completeLinuxDoOAuthRequest
struct
{
PendingOAuthToken
string
`json:"pending_oauth_token" binding:"required"`
InvitationCode
string
`json:"invitation_code" binding:"required"`
}
// CompleteLinuxDoOAuthRegistration completes a pending OAuth registration by validating
// the invitation code and creating the user account.
// POST /api/v1/auth/oauth/linuxdo/complete-registration
func
(
h
*
AuthHandler
)
CompleteLinuxDoOAuthRegistration
(
c
*
gin
.
Context
)
{
var
req
completeLinuxDoOAuthRequest
if
err
:=
c
.
ShouldBindJSON
(
&
req
);
err
!=
nil
{
c
.
JSON
(
http
.
StatusBadRequest
,
gin
.
H
{
"error"
:
"INVALID_REQUEST"
,
"message"
:
err
.
Error
()})
return
}
email
,
username
,
err
:=
h
.
authService
.
VerifyPendingOAuthToken
(
req
.
PendingOAuthToken
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusUnauthorized
,
gin
.
H
{
"error"
:
"INVALID_TOKEN"
,
"message"
:
"invalid or expired registration token"
})
return
}
tokenPair
,
_
,
err
:=
h
.
authService
.
LoginOrRegisterOAuthWithTokenPair
(
c
.
Request
.
Context
(),
email
,
username
,
req
.
InvitationCode
)
if
err
!=
nil
{
statusCode
:=
http
.
StatusBadRequest
c
.
JSON
(
statusCode
,
gin
.
H
{
"error"
:
infraerrors
.
Reason
(
err
),
"message"
:
infraerrors
.
Message
(
err
),
})
return
}
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"access_token"
:
tokenPair
.
AccessToken
,
"refresh_token"
:
tokenPair
.
RefreshToken
,
"expires_in"
:
tokenPair
.
ExpiresIn
,
"token_type"
:
"Bearer"
,
})
}
func
(
h
*
AuthHandler
)
getLinuxDoOAuthConfig
(
ctx
context
.
Context
)
(
config
.
LinuxDoConnectConfig
,
error
)
{
if
h
!=
nil
&&
h
.
settingSvc
!=
nil
{
return
h
.
settingSvc
.
GetLinuxDoConnectOAuthConfig
(
ctx
)
...
...
backend/internal/server/routes/auth.go
View file @
c069b3b1
...
...
@@ -61,6 +61,12 @@ func RegisterAuthRoutes(
}),
h
.
Auth
.
ResetPassword
)
auth
.
GET
(
"/oauth/linuxdo/start"
,
h
.
Auth
.
LinuxDoOAuthStart
)
auth
.
GET
(
"/oauth/linuxdo/callback"
,
h
.
Auth
.
LinuxDoOAuthCallback
)
auth
.
POST
(
"/oauth/linuxdo/complete-registration"
,
rateLimiter
.
LimitWithOptions
(
"oauth-linuxdo-complete"
,
10
,
time
.
Minute
,
middleware
.
RateLimitOptions
{
FailureMode
:
middleware
.
RateLimitFailClose
,
}),
h
.
Auth
.
CompleteLinuxDoOAuthRegistration
,
)
}
// 公开设置(无需认证)
...
...
backend/internal/service/auth_service.go
View file @
c069b3b1
...
...
@@ -21,24 +21,25 @@ import (
)
var
(
ErrInvalidCredentials
=
infraerrors
.
Unauthorized
(
"INVALID_CREDENTIALS"
,
"invalid email or password"
)
ErrUserNotActive
=
infraerrors
.
Forbidden
(
"USER_NOT_ACTIVE"
,
"user is not active"
)
ErrEmailExists
=
infraerrors
.
Conflict
(
"EMAIL_EXISTS"
,
"email already exists"
)
ErrEmailReserved
=
infraerrors
.
BadRequest
(
"EMAIL_RESERVED"
,
"email is reserved"
)
ErrInvalidToken
=
infraerrors
.
Unauthorized
(
"INVALID_TOKEN"
,
"invalid token"
)
ErrTokenExpired
=
infraerrors
.
Unauthorized
(
"TOKEN_EXPIRED"
,
"token has expired"
)
ErrAccessTokenExpired
=
infraerrors
.
Unauthorized
(
"ACCESS_TOKEN_EXPIRED"
,
"access token has expired"
)
ErrTokenTooLarge
=
infraerrors
.
BadRequest
(
"TOKEN_TOO_LARGE"
,
"token too large"
)
ErrTokenRevoked
=
infraerrors
.
Unauthorized
(
"TOKEN_REVOKED"
,
"token has been revoked"
)
ErrRefreshTokenInvalid
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_INVALID"
,
"invalid refresh token"
)
ErrRefreshTokenExpired
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_EXPIRED"
,
"refresh token has expired"
)
ErrRefreshTokenReused
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_REUSED"
,
"refresh token has been reused"
)
ErrEmailVerifyRequired
=
infraerrors
.
BadRequest
(
"EMAIL_VERIFY_REQUIRED"
,
"email verification is required"
)
ErrEmailSuffixNotAllowed
=
infraerrors
.
BadRequest
(
"EMAIL_SUFFIX_NOT_ALLOWED"
,
"email suffix is not allowed"
)
ErrRegDisabled
=
infraerrors
.
Forbidden
(
"REGISTRATION_DISABLED"
,
"registration is currently disabled"
)
ErrServiceUnavailable
=
infraerrors
.
ServiceUnavailable
(
"SERVICE_UNAVAILABLE"
,
"service temporarily unavailable"
)
ErrInvitationCodeRequired
=
infraerrors
.
BadRequest
(
"INVITATION_CODE_REQUIRED"
,
"invitation code is required"
)
ErrInvitationCodeInvalid
=
infraerrors
.
BadRequest
(
"INVITATION_CODE_INVALID"
,
"invalid or used invitation code"
)
ErrInvalidCredentials
=
infraerrors
.
Unauthorized
(
"INVALID_CREDENTIALS"
,
"invalid email or password"
)
ErrUserNotActive
=
infraerrors
.
Forbidden
(
"USER_NOT_ACTIVE"
,
"user is not active"
)
ErrEmailExists
=
infraerrors
.
Conflict
(
"EMAIL_EXISTS"
,
"email already exists"
)
ErrEmailReserved
=
infraerrors
.
BadRequest
(
"EMAIL_RESERVED"
,
"email is reserved"
)
ErrInvalidToken
=
infraerrors
.
Unauthorized
(
"INVALID_TOKEN"
,
"invalid token"
)
ErrTokenExpired
=
infraerrors
.
Unauthorized
(
"TOKEN_EXPIRED"
,
"token has expired"
)
ErrAccessTokenExpired
=
infraerrors
.
Unauthorized
(
"ACCESS_TOKEN_EXPIRED"
,
"access token has expired"
)
ErrTokenTooLarge
=
infraerrors
.
BadRequest
(
"TOKEN_TOO_LARGE"
,
"token too large"
)
ErrTokenRevoked
=
infraerrors
.
Unauthorized
(
"TOKEN_REVOKED"
,
"token has been revoked"
)
ErrRefreshTokenInvalid
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_INVALID"
,
"invalid refresh token"
)
ErrRefreshTokenExpired
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_EXPIRED"
,
"refresh token has expired"
)
ErrRefreshTokenReused
=
infraerrors
.
Unauthorized
(
"REFRESH_TOKEN_REUSED"
,
"refresh token has been reused"
)
ErrEmailVerifyRequired
=
infraerrors
.
BadRequest
(
"EMAIL_VERIFY_REQUIRED"
,
"email verification is required"
)
ErrEmailSuffixNotAllowed
=
infraerrors
.
BadRequest
(
"EMAIL_SUFFIX_NOT_ALLOWED"
,
"email suffix is not allowed"
)
ErrRegDisabled
=
infraerrors
.
Forbidden
(
"REGISTRATION_DISABLED"
,
"registration is currently disabled"
)
ErrServiceUnavailable
=
infraerrors
.
ServiceUnavailable
(
"SERVICE_UNAVAILABLE"
,
"service temporarily unavailable"
)
ErrInvitationCodeRequired
=
infraerrors
.
BadRequest
(
"INVITATION_CODE_REQUIRED"
,
"invitation code is required"
)
ErrInvitationCodeInvalid
=
infraerrors
.
BadRequest
(
"INVITATION_CODE_INVALID"
,
"invalid or used invitation code"
)
ErrOAuthInvitationRequired
=
infraerrors
.
Forbidden
(
"OAUTH_INVITATION_REQUIRED"
,
"invitation code required to complete oauth registration"
)
)
// maxTokenLength 限制 token 大小,避免超长 header 触发解析时的异常内存分配。
...
...
@@ -523,9 +524,10 @@ func (s *AuthService) LoginOrRegisterOAuth(ctx context.Context, email, username
return
token
,
user
,
nil
}
// LoginOrRegisterOAuthWithTokenPair 用于第三方 OAuth/SSO 登录,返回完整的 TokenPair
// 与 LoginOrRegisterOAuth 功能相同,但返回 TokenPair 而非单个 token
func
(
s
*
AuthService
)
LoginOrRegisterOAuthWithTokenPair
(
ctx
context
.
Context
,
email
,
username
string
)
(
*
TokenPair
,
*
User
,
error
)
{
// LoginOrRegisterOAuthWithTokenPair 用于第三方 OAuth/SSO 登录,返回完整的 TokenPair。
// 与 LoginOrRegisterOAuth 功能相同,但返回 TokenPair 而非单个 token。
// invitationCode 仅在邀请码注册模式下新用户注册时使用;已有账号登录时忽略。
func
(
s
*
AuthService
)
LoginOrRegisterOAuthWithTokenPair
(
ctx
context
.
Context
,
email
,
username
,
invitationCode
string
)
(
*
TokenPair
,
*
User
,
error
)
{
// 检查 refreshTokenCache 是否可用
if
s
.
refreshTokenCache
==
nil
{
return
nil
,
nil
,
errors
.
New
(
"refresh token cache not configured"
)
...
...
@@ -552,6 +554,22 @@ func (s *AuthService) LoginOrRegisterOAuthWithTokenPair(ctx context.Context, ema
return
nil
,
nil
,
ErrRegDisabled
}
// 检查是否需要邀请码
var
invitationRedeemCode
*
RedeemCode
if
s
.
settingService
!=
nil
&&
s
.
settingService
.
IsInvitationCodeEnabled
(
ctx
)
{
if
invitationCode
==
""
{
return
nil
,
nil
,
ErrOAuthInvitationRequired
}
redeemCode
,
err
:=
s
.
redeemRepo
.
GetByCode
(
ctx
,
invitationCode
)
if
err
!=
nil
{
return
nil
,
nil
,
ErrInvitationCodeInvalid
}
if
redeemCode
.
Type
!=
RedeemTypeInvitation
||
redeemCode
.
Status
!=
StatusUnused
{
return
nil
,
nil
,
ErrInvitationCodeInvalid
}
invitationRedeemCode
=
redeemCode
}
randomPassword
,
err
:=
randomHexString
(
32
)
if
err
!=
nil
{
logger
.
LegacyPrintf
(
"service.auth"
,
"[Auth] Failed to generate random password for oauth signup: %v"
,
err
)
...
...
@@ -593,6 +611,11 @@ func (s *AuthService) LoginOrRegisterOAuthWithTokenPair(ctx context.Context, ema
}
else
{
user
=
newUser
s
.
assignDefaultSubscriptions
(
ctx
,
user
.
ID
)
if
invitationRedeemCode
!=
nil
{
if
err
:=
s
.
redeemRepo
.
Use
(
ctx
,
invitationRedeemCode
.
ID
,
user
.
ID
);
err
!=
nil
{
logger
.
LegacyPrintf
(
"service.auth"
,
"[Auth] Failed to mark invitation code as used for oauth user %d: %v"
,
user
.
ID
,
err
)
}
}
}
}
else
{
logger
.
LegacyPrintf
(
"service.auth"
,
"[Auth] Database error during oauth login: %v"
,
err
)
...
...
@@ -618,6 +641,55 @@ func (s *AuthService) LoginOrRegisterOAuthWithTokenPair(ctx context.Context, ema
return
tokenPair
,
user
,
nil
}
// pendingOAuthTokenTTL is the validity period for pending OAuth tokens.
const
pendingOAuthTokenTTL
=
10
*
time
.
Minute
type
pendingOAuthClaims
struct
{
Email
string
`json:"email"`
Username
string
`json:"username"`
jwt
.
RegisteredClaims
}
// CreatePendingOAuthToken generates a short-lived JWT that carries the OAuth identity
// while waiting for the user to supply an invitation code.
func
(
s
*
AuthService
)
CreatePendingOAuthToken
(
email
,
username
string
)
(
string
,
error
)
{
now
:=
time
.
Now
()
claims
:=
&
pendingOAuthClaims
{
Email
:
email
,
Username
:
username
,
RegisteredClaims
:
jwt
.
RegisteredClaims
{
ExpiresAt
:
jwt
.
NewNumericDate
(
now
.
Add
(
pendingOAuthTokenTTL
)),
IssuedAt
:
jwt
.
NewNumericDate
(
now
),
NotBefore
:
jwt
.
NewNumericDate
(
now
),
},
}
token
:=
jwt
.
NewWithClaims
(
jwt
.
SigningMethodHS256
,
claims
)
return
token
.
SignedString
([]
byte
(
s
.
cfg
.
JWT
.
Secret
))
}
// VerifyPendingOAuthToken validates a pending OAuth token and returns the embedded identity.
// Returns ErrInvalidToken when the token is invalid or expired.
func
(
s
*
AuthService
)
VerifyPendingOAuthToken
(
tokenStr
string
)
(
email
,
username
string
,
err
error
)
{
if
len
(
tokenStr
)
>
maxTokenLength
{
return
""
,
""
,
ErrInvalidToken
}
parser
:=
jwt
.
NewParser
(
jwt
.
WithValidMethods
([]
string
{
jwt
.
SigningMethodHS256
.
Name
}))
token
,
parseErr
:=
parser
.
ParseWithClaims
(
tokenStr
,
&
pendingOAuthClaims
{},
func
(
t
*
jwt
.
Token
)
(
any
,
error
)
{
if
_
,
ok
:=
t
.
Method
.
(
*
jwt
.
SigningMethodHMAC
);
!
ok
{
return
nil
,
fmt
.
Errorf
(
"unexpected signing method: %v"
,
t
.
Header
[
"alg"
])
}
return
[]
byte
(
s
.
cfg
.
JWT
.
Secret
),
nil
})
if
parseErr
!=
nil
{
return
""
,
""
,
ErrInvalidToken
}
claims
,
ok
:=
token
.
Claims
.
(
*
pendingOAuthClaims
)
if
!
ok
||
!
token
.
Valid
{
return
""
,
""
,
ErrInvalidToken
}
return
claims
.
Email
,
claims
.
Username
,
nil
}
func
(
s
*
AuthService
)
assignDefaultSubscriptions
(
ctx
context
.
Context
,
userID
int64
)
{
if
s
.
settingService
==
nil
||
s
.
defaultSubAssigner
==
nil
||
userID
<=
0
{
return
...
...
frontend/src/api/auth.ts
View file @
c069b3b1
...
...
@@ -335,6 +335,28 @@ export async function resetPassword(request: ResetPasswordRequest): Promise<Rese
return
data
}
/**
* Complete LinuxDo OAuth registration by supplying an invitation code
* @param pendingOAuthToken - Short-lived JWT from the OAuth callback
* @param invitationCode - Invitation code entered by the user
* @returns Token pair on success
*/
export
async
function
completeLinuxDoOAuthRegistration
(
pendingOAuthToken
:
string
,
invitationCode
:
string
):
Promise
<
{
access_token
:
string
;
refresh_token
:
string
;
expires_in
:
number
;
token_type
:
string
}
>
{
const
{
data
}
=
await
apiClient
.
post
<
{
access_token
:
string
refresh_token
:
string
expires_in
:
number
token_type
:
string
}
>
(
'
/auth/oauth/linuxdo/complete-registration
'
,
{
pending_oauth_token
:
pendingOAuthToken
,
invitation_code
:
invitationCode
})
return
data
}
export
const
authAPI
=
{
login
,
login2FA
,
...
...
@@ -357,7 +379,8 @@ export const authAPI = {
forgotPassword
,
resetPassword
,
refreshToken
,
revokeAllSessions
revokeAllSessions
,
completeLinuxDoOAuthRegistration
}
export
default
authAPI
frontend/src/i18n/locales/en.ts
View file @
c069b3b1
...
...
@@ -433,7 +433,12 @@ export default {
callbackProcessing
:
'
Completing login, please wait...
'
,
callbackHint
:
'
If you are not redirected automatically, go back to the login page and try again.
'
,
callbackMissingToken
:
'
Missing login token, please try again.
'
,
backToLogin
:
'
Back to Login
'
backToLogin
:
'
Back to Login
'
,
invitationRequired
:
'
This Linux.do account is not yet registered. The site requires an invitation code — please enter one to complete registration.
'
,
invalidPendingToken
:
'
The registration token has expired. Please sign in with Linux.do again.
'
,
completeRegistration
:
'
Complete Registration
'
,
completing
:
'
Completing registration…
'
,
completeRegistrationFailed
:
'
Registration failed. Please check your invitation code and try again.
'
},
oauth
:
{
code
:
'
Code
'
,
...
...
frontend/src/i18n/locales/zh.ts
View file @
c069b3b1
...
...
@@ -432,7 +432,12 @@ export default {
callbackProcessing
:
'
正在验证登录信息,请稍候...
'
,
callbackHint
:
'
如果页面未自动跳转,请返回登录页重试。
'
,
callbackMissingToken
:
'
登录信息缺失,请返回重试。
'
,
backToLogin
:
'
返回登录
'
backToLogin
:
'
返回登录
'
,
invitationRequired
:
'
该 Linux.do 账号尚未注册,站点已开启邀请码注册,请输入邀请码以完成注册。
'
,
invalidPendingToken
:
'
注册凭证已失效,请重新使用 Linux.do 登录。
'
,
completeRegistration
:
'
完成注册
'
,
completing
:
'
正在完成注册...
'
,
completeRegistrationFailed
:
'
注册失败,请检查邀请码后重试。
'
},
oauth
:
{
code
:
'
授权码
'
,
...
...
frontend/src/views/auth/LinuxDoCallbackView.vue
View file @
c069b3b1
...
...
@@ -10,6 +10,36 @@
</p>
</div>
<transition
name=
"fade"
>
<div
v-if=
"needsInvitation"
class=
"space-y-4"
>
<p
class=
"text-sm text-gray-700 dark:text-gray-300"
>
{{
t
(
'
auth.linuxdo.invitationRequired
'
)
}}
</p>
<div>
<input
v-model=
"invitationCode"
type=
"text"
class=
"input w-full"
:placeholder=
"t('auth.invitationCodePlaceholder')"
:disabled=
"isSubmitting"
@
keyup.enter=
"handleSubmitInvitation"
/>
</div>
<transition
name=
"fade"
>
<p
v-if=
"invitationError"
class=
"text-sm text-red-600 dark:text-red-400"
>
{{
invitationError
}}
</p>
</transition>
<button
class=
"btn btn-primary w-full"
:disabled=
"isSubmitting || !invitationCode.trim()"
@
click=
"handleSubmitInvitation"
>
{{
isSubmitting
?
t
(
'
auth.linuxdo.completing
'
)
:
t
(
'
auth.linuxdo.completeRegistration
'
)
}}
</button>
</div>
</transition>
<transition
name=
"fade"
>
<div
v-if=
"errorMessage"
...
...
@@ -41,6 +71,7 @@ import { useI18n } from 'vue-i18n'
import
{
AuthLayout
}
from
'
@/components/layout
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
{
useAuthStore
,
useAppStore
}
from
'
@/stores
'
import
{
completeLinuxDoOAuthRegistration
}
from
'
@/api/auth
'
const
route
=
useRoute
()
const
router
=
useRouter
()
...
...
@@ -52,6 +83,14 @@ const appStore = useAppStore()
const
isProcessing
=
ref
(
true
)
const
errorMessage
=
ref
(
''
)
// Invitation code flow state
const
needsInvitation
=
ref
(
false
)
const
pendingOAuthToken
=
ref
(
''
)
const
invitationCode
=
ref
(
''
)
const
isSubmitting
=
ref
(
false
)
const
invitationError
=
ref
(
''
)
const
redirectTo
=
ref
(
'
/dashboard
'
)
function
parseFragmentParams
():
URLSearchParams
{
const
raw
=
typeof
window
!==
'
undefined
'
?
window
.
location
.
hash
:
''
const
hash
=
raw
.
startsWith
(
'
#
'
)
?
raw
.
slice
(
1
)
:
raw
...
...
@@ -67,6 +106,34 @@ function sanitizeRedirectPath(path: string | null | undefined): string {
return
path
}
async
function
handleSubmitInvitation
()
{
invitationError
.
value
=
''
if
(
!
invitationCode
.
value
.
trim
())
return
isSubmitting
.
value
=
true
try
{
const
tokenData
=
await
completeLinuxDoOAuthRegistration
(
pendingOAuthToken
.
value
,
invitationCode
.
value
.
trim
()
)
if
(
tokenData
.
refresh_token
)
{
localStorage
.
setItem
(
'
refresh_token
'
,
tokenData
.
refresh_token
)
}
if
(
tokenData
.
expires_in
)
{
localStorage
.
setItem
(
'
token_expires_at
'
,
String
(
Date
.
now
()
+
tokenData
.
expires_in
*
1000
))
}
await
authStore
.
setToken
(
tokenData
.
access_token
)
appStore
.
showSuccess
(
t
(
'
auth.loginSuccess
'
))
await
router
.
replace
(
redirectTo
.
value
)
}
catch
(
e
:
unknown
)
{
const
err
=
e
as
{
message
?:
string
;
response
?:
{
data
?:
{
message
?:
string
}
}
}
invitationError
.
value
=
err
.
response
?.
data
?.
message
||
err
.
message
||
t
(
'
auth.linuxdo.completeRegistrationFailed
'
)
}
finally
{
isSubmitting
.
value
=
false
}
}
onMounted
(
async
()
=>
{
const
params
=
parseFragmentParams
()
...
...
@@ -80,6 +147,19 @@ onMounted(async () => {
const
errorDesc
=
params
.
get
(
'
error_description
'
)
||
params
.
get
(
'
error_message
'
)
||
''
if
(
error
)
{
if
(
error
===
'
invitation_required
'
)
{
pendingOAuthToken
.
value
=
params
.
get
(
'
pending_oauth_token
'
)
||
''
redirectTo
.
value
=
sanitizeRedirectPath
(
params
.
get
(
'
redirect
'
))
if
(
!
pendingOAuthToken
.
value
)
{
errorMessage
.
value
=
t
(
'
auth.linuxdo.invalidPendingToken
'
)
appStore
.
showError
(
errorMessage
.
value
)
isProcessing
.
value
=
false
return
}
needsInvitation
.
value
=
true
isProcessing
.
value
=
false
return
}
errorMessage
.
value
=
errorDesc
||
error
appStore
.
showError
(
errorMessage
.
value
)
isProcessing
.
value
=
false
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment