-
-
Notifications
You must be signed in to change notification settings - Fork 50
Test PR - Ignore #3801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test PR - Ignore #3801
Changes from all commits
881858a
a11de78
a5b301b
8d4508f
2bae5b7
b56cb1a
9a8532a
feeea95
9e75369
dfc3ebd
803cd82
608a520
98ae917
78ef4d4
f06be9a
21631c0
0700d20
b6b2bc6
205ee2d
0f524e9
1f0a0d7
79339fa
b293252
4771e08
d626dac
ce91401
d19763e
ac5231d
82f6b93
0ddb07f
cb8ce7d
7b47889
22a9e10
36090b8
d71e01f
d8c4834
c6dd19c
0555f65
c40a9ba
ff6d120
7c2b08f
1f75cdd
61b99cb
7d40939
31e7f1b
c87d083
cc08f45
42c38c8
66387d4
a30defa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// ------------------------------------------------------------------------- | ||
// Styles for authentication pages (login, signup, etc.) | ||
// ------------------------------------------------------------------------- | ||
|
||
.portal-form-container { | ||
height: 55vh; | ||
padding: 10%; | ||
} | ||
|
||
.portal-form-inputs { | ||
display: flex; | ||
flex-direction: column; | ||
width: 50%; | ||
margin-bottom: 15px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import Foundation | ||
import Dependencies | ||
import Fluent | ||
import Plot | ||
import Vapor | ||
import SotoCognitoAuthentication | ||
import SotoCognitoIdentityProvider | ||
import SotoCognitoIdentity | ||
|
||
extension Portal { | ||
|
||
enum DeleteAccountController { | ||
@Sendable | ||
static func deleteAccount(req: Request) async throws -> Response { | ||
@Dependency(\.cognito) var cognito | ||
do { | ||
try await cognito.deleteUser(req: req) | ||
req.auth.logout(AuthenticatedUser.self) | ||
req.session.unauthenticate(AuthenticatedUser.self) | ||
req.session.destroy() | ||
return req.redirect(to: SiteURL.home.relativeURL()) | ||
} catch { | ||
return PortalPage.View(path: SiteURL.portal.relativeURL(), model: PortalPage.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)")).document().encodeResponse(status: .internalServerError) | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,32 @@ | ||||||||||||||||||
import Fluent | ||||||||||||||||||
import Dependencies | ||||||||||||||||||
import Plot | ||||||||||||||||||
import Vapor | ||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||
|
||||||||||||||||||
Comment on lines
+1
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Apache 2.0 License preamble. The file is missing the required Apache 2.0 License preamble that should be included at the top of all Swift files according to the coding guidelines. Add the Apache 2.0 License preamble at the top of the file: +//
+// Copyright © 2023 Swift Package Index. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
import Fluent
import Dependencies 🤖 Prompt for AI Agents
|
||||||||||||||||||
extension Portal { | ||||||||||||||||||
|
||||||||||||||||||
enum ForgotPasswordController { | ||||||||||||||||||
@Sendable | ||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||
return ForgotPassword.View(path: req.url.path, model: ForgotPassword.Model()).document() | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
@Sendable | ||||||||||||||||||
static func forgotPasswordEmail(req: Request) async throws -> HTML { | ||||||||||||||||||
@Dependency(\.cognito) var cognito | ||||||||||||||||||
struct Credentials: Content { | ||||||||||||||||||
var email: String | ||||||||||||||||||
} | ||||||||||||||||||
do { | ||||||||||||||||||
let user = try req.content.decode(Credentials.self) | ||||||||||||||||||
try await cognito.forgotPassword(req: req, username: user.email) | ||||||||||||||||||
return Reset.View(path: SiteURL.resetPassword.relativeURL(), model: Reset.Model(email: user.email)).document() | ||||||||||||||||||
} catch { | ||||||||||||||||||
return ForgotPassword.View(path: req.url.path, model: ForgotPassword.Model(errorMessage: "An error occurred: \(error.localizedDescription)")).document() | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using more user-friendly error messages. Directly exposing - return ForgotPassword.View(path: req.url.path, model: ForgotPassword.Model(errorMessage: "An error occurred: \(error.localizedDescription)")).document()
+ let errorMessage = "We couldn't process your password reset request. Please try again later."
+ // Log the actual error for debugging
+ req.logger.error("Password reset error: \(error.localizedDescription)")
+ return ForgotPassword.View(path: req.url.path, model: ForgotPassword.Model(errorMessage: errorMessage)).document() 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,56 @@ | ||||||||||||||||||||||||||||||||||
import Foundation | ||||||||||||||||||||||||||||||||||
import Dependencies | ||||||||||||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
enum Portal { | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
enum LoginController { | ||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||
return Login.View(path: req.url.path, model: Login.Model(errorMessage: "")).document() | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||
static func login(req: Request) async throws -> Response { | ||||||||||||||||||||||||||||||||||
@Dependency(\.cognito) var cognito | ||||||||||||||||||||||||||||||||||
struct UserCreds: Content { | ||||||||||||||||||||||||||||||||||
var email: String | ||||||||||||||||||||||||||||||||||
var password: String | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
do { | ||||||||||||||||||||||||||||||||||
let user = try req.content.decode(UserCreds.self) | ||||||||||||||||||||||||||||||||||
let response = try await cognito.authenticate(req: req, username: user.email, password: user.password) | ||||||||||||||||||||||||||||||||||
switch response { | ||||||||||||||||||||||||||||||||||
case .authenticated(let authenticatedResponse): | ||||||||||||||||||||||||||||||||||
let user = AuthenticatedUser(accessToken: authenticatedResponse.accessToken!) | ||||||||||||||||||||||||||||||||||
req.auth.login(user) | ||||||||||||||||||||||||||||||||||
case .challenged(_): // Cognito is not configured to send challenges, so we should never receive this response. | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
Comment on lines
+28
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid force-unwrap of
-case .authenticated(let authenticatedResponse):
- let user = AuthenticatedUser(accessToken: authenticatedResponse.accessToken!)
- req.auth.login(user)
-case .challenged(_):
- break
+case .authenticated(let authenticatedResponse):
+ guard let token = authenticatedResponse.accessToken else {
+ throw Abort(.internalServerError, reason: "Missing access token in Cognito response")
+ }
+ req.auth.login(AuthenticatedUser(accessToken: token))
+case .challenged(let challenge):
+ throw Abort(.unauthorized, reason: "Unexpected Cognito challenge: \(challenge)") 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||
return req.redirect(to: SiteURL.portal.relativeURL(), redirectType: .normal) | ||||||||||||||||||||||||||||||||||
} catch let error as SotoCognitoError { | ||||||||||||||||||||||||||||||||||
var model = Login.Model(errorMessage: "There was an error. Please try again.") | ||||||||||||||||||||||||||||||||||
switch error { | ||||||||||||||||||||||||||||||||||
case .unauthorized(let reason): | ||||||||||||||||||||||||||||||||||
model = Login.Model(errorMessage: reason ?? "There was an error. Please try again.") | ||||||||||||||||||||||||||||||||||
case .unexpectedResult(let reason): | ||||||||||||||||||||||||||||||||||
model = Login.Model(errorMessage: reason ?? "There was an error. Please try again.") | ||||||||||||||||||||||||||||||||||
case .invalidPublicKey: | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
return Login.View(path: req.url.path, model: model).document().encodeResponse(status: .unauthorized) | ||||||||||||||||||||||||||||||||||
} catch let error as AWSClientError { | ||||||||||||||||||||||||||||||||||
return Login.View(path: SiteURL.login.relativeURL(), model: Login.Model(errorMessage: "An AWS client error occurred: \(error.errorCode)")).document().encodeResponse(status: .unauthorized) | ||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||
return Login.View(path: SiteURL.login.relativeURL(), model: Login.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)")).document().encodeResponse(status: .unauthorized) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,21 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Foundation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Apache 2.0 License preamble. According to the coding guidelines, every Swift file should have the Apache 2.0 License preamble at the top, commented to suit the language. Add the license preamble at the top of the file: +// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
import Foundation
import Fluent
import Plot
import Vapor
import SotoCognitoAuthentication
import SotoCognitoIdentityProvider
import SotoCognitoIdentity 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
extension Portal { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enum LogoutController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func logout(req: Request) async throws -> Response { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req.auth.logout(AuthenticatedUser.self) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req.session.unauthenticate(AuthenticatedUser.self) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
req.session.destroy() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return req.redirect(to: SiteURL.home.relativeURL()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,14 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoAuthenticationKit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
extension Portal { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enum PortalController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return PortalPage.View(path: req.url.path, model: PortalPage.Model()).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Apache License preamble According to the coding guidelines, all Swift files should include the Apache 2.0 License preamble at the top, commented to suit the language. Please add the standard license header. +// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
import Fluent
import Plot
import Vapor
import SotoCognitoAuthenticationKit 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,40 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Dependencies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Apache 2.0 License preamble. According to the coding guidelines, every Swift file should have the Apache 2.0 License preamble at the top, commented to suit the language. Add the license preamble at the top of the file: +// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
import Fluent
import Dependencies
import Plot
import Vapor
import SotoCognitoAuthentication
import SotoCognitoIdentityProvider
import SotoCognitoIdentity 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
extension Portal { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enum ResetController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Reset.View(path: req.url.path, model: Reset.Model()).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func resetPassword(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Dependency(\.cognito) var cognito | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
struct UserInfo: Content { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var email: String | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var password: String | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var confirmationCode: String | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
do { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let user = try req.content.decode(UserInfo.self) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try await cognito.resetPassword(req: req, username: user.email, password: user.password, confirmationCode: user.confirmationCode) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let model = SuccessfulChange.Model(successMessage: "Successfully changed password") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return SuccessfulChange.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch let error as AWSErrorType { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let model = Reset.Model(errorMessage: errorMessage) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Reset.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let model = Reset.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Reset.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+19
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation and escape HTML in error messages. The method handles the password reset flow well, but there are two potential improvements:
Consider applying these improvements: @Sendable
static func resetPassword(req: Request) async throws -> HTML {
@Dependency(\.cognito) var cognito
struct UserInfo: Content {
var email: String
var password: String
var confirmationCode: String
}
do {
let user = try req.content.decode(UserInfo.self)
+ // Validate input
+ guard !user.email.isEmpty, !user.password.isEmpty, !user.confirmationCode.isEmpty else {
+ throw Abort(.badRequest, reason: "All fields are required")
+ }
+
try await cognito.resetPassword(req: req, username: user.email, password: user.password, confirmationCode: user.confirmationCode)
let model = SuccessfulChange.Model(successMessage: "Successfully changed password")
return SuccessfulChange.View(path: req.url.path, model: model).document()
} catch let error as AWSErrorType {
- let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)"
+ let errorMessage = (error.message != nil) ? "There was an error: \(error.message?.description.htmlEscaped ?? "")" : "There was an error: \(error.localizedDescription.htmlEscaped)"
let model = Reset.Model(errorMessage: errorMessage)
return Reset.View(path: req.url.path, model: model).document()
} catch {
- let model = Reset.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)")
+ let model = Reset.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription.htmlEscaped)")
return Reset.View(path: req.url.path, model: model).document()
}
} Note: You'll need to ensure that an 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,38 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Dependencies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Apache 2.0 License preamble. According to the coding guidelines, every Swift file should have the Apache 2.0 License preamble at the top, commented to suit the language. Add the license preamble at the top of the file: +// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
import Fluent
import Dependencies
import Plot
import Vapor
import SotoCognitoAuthentication
import SotoCognitoIdentityProvider
import SotoCognitoIdentity 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
extension Portal { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enum SignupController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Signup.View(path: req.url.path, model: Signup.Model(errorMessage: "")).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static func signup(req: Request) async throws -> HTML { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Dependency(\.cognito) var cognito | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
struct UserCreds: Content { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var email: String | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var password: String | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
do { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let user = try req.content.decode(UserCreds.self) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try await cognito.signup(req: req, username: user.email, password: user.password) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Verify.View(path: SiteURL.verify.relativeURL(), model: Verify.Model(email: user.email)).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch let error as AWSErrorType { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let model = Signup.Model(errorMessage: errorMessage) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Signup.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Signup.View(path: SiteURL.signup.relativeURL(), model: Signup.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)")).document() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+18
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation, escape HTML in error messages, and use consistent paths. The method handles the signup flow well, but there are three potential improvements:
Consider applying these improvements: @Sendable
static func signup(req: Request) async throws -> HTML {
@Dependency(\.cognito) var cognito
struct UserCreds: Content {
var email: String
var password: String
}
do {
let user = try req.content.decode(UserCreds.self)
+ // Validate input
+ guard !user.email.isEmpty, !user.password.isEmpty else {
+ throw Abort(.badRequest, reason: "Email and password are required")
+ }
+
try await cognito.signup(req: req, username: user.email, password: user.password)
return Verify.View(path: SiteURL.verify.relativeURL(), model: Verify.Model(email: user.email)).document()
} catch let error as AWSErrorType {
- let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)"
+ let errorMessage = (error.message != nil) ? "There was an error: \(error.message?.description.htmlEscaped ?? "")" : "There was an error: \(error.localizedDescription.htmlEscaped)"
let model = Signup.Model(errorMessage: errorMessage)
return Signup.View(path: req.url.path, model: model).document()
} catch {
- return Signup.View(path: SiteURL.signup.relativeURL(), model: Signup.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription)")).document()
+ return Signup.View(path: req.url.path, model: Signup.Model(errorMessage: "An unknown error occurred: \(error.localizedDescription.htmlEscaped)")).document()
}
} Note: You'll need to ensure that an 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,42 @@ | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
import Fluent | ||||||||||||||||||||||||
import Plot | ||||||||||||||||||||||||
import Vapor | ||||||||||||||||||||||||
import SotoCognitoAuthentication | ||||||||||||||||||||||||
import SotoCognitoIdentityProvider | ||||||||||||||||||||||||
import SotoCognitoIdentity | ||||||||||||||||||||||||
import Dependencies | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
extension Portal { | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
enum VerifyController { | ||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||
static func show(req: Request) async throws -> HTML { | ||||||||||||||||||||||||
return Verify.View(path: req.url.path, model: Verify.Model(email: "")).document() | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
@Sendable | ||||||||||||||||||||||||
static func verify(req: Request) async throws -> HTML { | ||||||||||||||||||||||||
@Dependency(\.cognito) var cognito | ||||||||||||||||||||||||
struct VerifyInformation: Content { | ||||||||||||||||||||||||
var email: String | ||||||||||||||||||||||||
var confirmationCode: String | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
do { | ||||||||||||||||||||||||
let info = try req.content.decode(VerifyInformation.self) | ||||||||||||||||||||||||
try await cognito.confirmSignUp(req: req, username: info.email, confirmationCode: info.confirmationCode) | ||||||||||||||||||||||||
let model = SuccessfulChange.Model(successMessage: "Successfully confirmed signup") | ||||||||||||||||||||||||
return SuccessfulChange.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||
} catch let error as AWSErrorType { | ||||||||||||||||||||||||
let info = try req.content.decode(VerifyInformation.self) | ||||||||||||||||||||||||
let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)" | ||||||||||||||||||||||||
let model = Verify.Model(email: info.email, errorMessage: errorMessage) | ||||||||||||||||||||||||
return Verify.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||
Comment on lines
+30
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interpolating optional produces
-let errorMessage = (error.message != nil) ? "There was an error: \(error.message)" : "There was an error: \(error.localizedDescription)"
+let details = error.message ?? error.localizedDescription
+let errorMessage = "There was an error: \(details)" 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||
let info = try req.content.decode(VerifyInformation.self) | ||||||||||||||||||||||||
let model = Verify.Model(email: info.email, errorMessage: "An unknown error occurred: \(error.localizedDescription)") | ||||||||||||||||||||||||
return Verify.View(path: req.url.path, model: model).document() | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Apache License preamble
According to the coding guidelines, all Swift files should include the Apache 2.0 License preamble at the top, commented to suit the language. Please add the standard license header.
📝 Committable suggestion
🤖 Prompt for AI Agents