...
This commit is contained in:
parent
4274fdaf93
commit
433606eb25
@ -2,16 +2,6 @@
|
||||
|
||||
This guide provides detailed instructions on how to integrate Gitea authentication into your Hostbasket application.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Introduction](#introduction)
|
||||
2. [Prerequisites](#prerequisites)
|
||||
3. [Setting Up Gitea OAuth Application](#setting-up-gitea-oauth-application)
|
||||
4. [Configuring Hostbasket for Gitea Authentication](#configuring-hostbasket-for-gitea-authentication)
|
||||
5. [Implementing the OAuth Flow](#implementing-the-oauth-flow)
|
||||
6. [Testing the Integration](#testing-the-integration)
|
||||
7. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Introduction
|
||||
|
||||
Gitea is a self-hosted Git service that provides a GitHub-like interface. By integrating Gitea authentication into your Hostbasket application, you can allow users to log in using their Gitea accounts, simplifying the authentication process and providing a seamless experience.
|
||||
@ -27,7 +17,7 @@ Before you begin, ensure you have:
|
||||
## Setting Up Gitea OAuth Application
|
||||
|
||||
1. Log in to your Gitea instance as an administrator
|
||||
2. Navigate to **Site Administration** > **Applications**
|
||||
2. Navigate to **Site Administration** > **Integrations** > **Applications**
|
||||
3. Click **Create a New OAuth2 Application**
|
||||
4. Fill in the application details:
|
||||
- **Application Name**: Hostbasket
|
||||
@ -96,11 +86,11 @@ impl GiteaOAuthConfig {
|
||||
.expect("Missing GITEA_CLIENT_SECRET environment variable");
|
||||
let instance_url = env::var("GITEA_INSTANCE_URL")
|
||||
.expect("Missing GITEA_INSTANCE_URL environment variable");
|
||||
|
||||
|
||||
// Create OAuth client
|
||||
let auth_url = format!("{}/login/oauth/authorize", instance_url);
|
||||
let token_url = format!("{}/login/oauth/access_token", instance_url);
|
||||
|
||||
|
||||
let client = BasicClient::new(
|
||||
ClientId::new(client_id),
|
||||
Some(ClientSecret::new(client_secret)),
|
||||
@ -110,7 +100,7 @@ impl GiteaOAuthConfig {
|
||||
.set_redirect_uri(
|
||||
RedirectUrl::new("http://localhost:9999/auth/gitea/callback".to_string()).unwrap(),
|
||||
);
|
||||
|
||||
|
||||
Self {
|
||||
client,
|
||||
instance_url,
|
||||
@ -158,16 +148,16 @@ impl GiteaAuthController {
|
||||
.add_scope(Scope::new("read:user".to_string()))
|
||||
.add_scope(Scope::new("user:email".to_string()))
|
||||
.url();
|
||||
|
||||
|
||||
// Store the CSRF token in the session
|
||||
session.insert("oauth_csrf_token", csrf_token.secret())?;
|
||||
|
||||
|
||||
// Redirect to the authorization URL
|
||||
Ok(HttpResponse::Found()
|
||||
.append_header((header::LOCATION, auth_url.to_string()))
|
||||
.finish())
|
||||
}
|
||||
|
||||
|
||||
// Handle the OAuth callback
|
||||
pub async fn callback(
|
||||
oauth_config: web::Data<GiteaOAuthConfig>,
|
||||
@ -177,11 +167,11 @@ impl GiteaAuthController {
|
||||
// Verify the CSRF token
|
||||
let csrf_token = session.get::<String>("oauth_csrf_token")?
|
||||
.ok_or_else(|| actix_web::error::ErrorBadRequest("Missing CSRF token"))?;
|
||||
|
||||
|
||||
if csrf_token != query.state {
|
||||
return Err(actix_web::error::ErrorBadRequest("Invalid CSRF token"));
|
||||
}
|
||||
|
||||
|
||||
// Exchange the authorization code for an access token
|
||||
let token = oauth_config
|
||||
.client
|
||||
@ -189,11 +179,11 @@ impl GiteaAuthController {
|
||||
.request_async(oauth2::reqwest::async_http_client)
|
||||
.await
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("Token exchange error: {}", e)))?;
|
||||
|
||||
|
||||
// Get the user information from Gitea
|
||||
let client = Client::new();
|
||||
let user_info_url = format!("{}/api/v1/user", oauth_config.instance_url);
|
||||
|
||||
|
||||
let gitea_user = client
|
||||
.get(&user_info_url)
|
||||
.bearer_auth(token.access_token().secret())
|
||||
@ -203,26 +193,26 @@ impl GiteaAuthController {
|
||||
.json::<crate::config::oauth::GiteaUser>()
|
||||
.await
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("JSON parsing error: {}", e)))?;
|
||||
|
||||
|
||||
// Create or update the user in your system
|
||||
let mut user = User::new(
|
||||
gitea_user.full_name.clone(),
|
||||
gitea_user.email.clone(),
|
||||
);
|
||||
|
||||
|
||||
// Set the user ID and role
|
||||
user.id = Some(gitea_user.id as i32);
|
||||
user.role = UserRole::User;
|
||||
|
||||
|
||||
// Generate JWT token
|
||||
let token = AuthController::generate_token(&user.email, &user.role)
|
||||
.map_err(|_| actix_web::error::ErrorInternalServerError("Failed to generate token"))?;
|
||||
|
||||
|
||||
// Store user data in session
|
||||
let user_json = serde_json::to_string(&user).unwrap();
|
||||
session.insert("user", &user_json)?;
|
||||
session.insert("auth_token", &token)?;
|
||||
|
||||
|
||||
// Create a cookie with the JWT token
|
||||
let cookie = Cookie::build("auth_token", token)
|
||||
.path("/")
|
||||
@ -230,7 +220,7 @@ impl GiteaAuthController {
|
||||
.secure(false) // Set to true in production with HTTPS
|
||||
.max_age(actix_web::cookie::time::Duration::hours(24))
|
||||
.finish();
|
||||
|
||||
|
||||
// Redirect to the home page with JWT token in cookie
|
||||
Ok(HttpResponse::Found()
|
||||
.cookie(cookie)
|
||||
@ -258,7 +248,7 @@ use crate::config::oauth::GiteaOAuthConfig;
|
||||
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
// Create the OAuth configuration
|
||||
let oauth_config = web::Data::new(GiteaOAuthConfig::new());
|
||||
|
||||
|
||||
// Configure session middleware with the consistent key
|
||||
let session_middleware = SessionMiddleware::builder(
|
||||
CookieSessionStore::default(),
|
||||
@ -273,7 +263,7 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
.wrap(session_middleware)
|
||||
.app_data(oauth_config.clone())
|
||||
// Existing routes...
|
||||
|
||||
|
||||
// Gitea OAuth routes
|
||||
.route("/auth/gitea", web::get().to(GiteaAuthController::login))
|
||||
.route("/auth/gitea/callback", web::get().to(GiteaAuthController::callback))
|
||||
@ -310,9 +300,9 @@ Update your login page template (`src/views/auth/login.html`) to include a "Logi
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</form>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
<div class="text-center">
|
||||
<p>Or login with:</p>
|
||||
<a href="/auth/gitea" class="btn btn-secondary">
|
||||
|
@ -1,12 +1,8 @@
|
||||
#[cfg(feature = "gitea")]
|
||||
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
|
||||
#[cfg(feature = "gitea")]
|
||||
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
||||
|
||||
/// Gitea OAuth configuration
|
||||
#[cfg(feature = "gitea")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GiteaOAuthConfig {
|
||||
/// OAuth client
|
||||
@ -15,7 +11,6 @@ pub struct GiteaOAuthConfig {
|
||||
pub instance_url: String,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gitea")]
|
||||
impl GiteaOAuthConfig {
|
||||
/// Creates a new Gitea OAuth configuration
|
||||
pub fn new() -> Self {
|
||||
@ -53,7 +48,6 @@ impl GiteaOAuthConfig {
|
||||
}
|
||||
|
||||
/// Gitea user information structure
|
||||
#[cfg(feature = "gitea")]
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct GiteaUser {
|
||||
/// User ID
|
||||
|
@ -1,12 +1,13 @@
|
||||
use actix_web::{web, HttpResponse, Responder, Result, http::header, cookie::Cookie};
|
||||
use actix_session::Session;
|
||||
use tera::Tera;
|
||||
use crate::models::user::{User, LoginCredentials, RegistrationData, UserRole};
|
||||
use crate::models::user::{LoginCredentials, RegistrationData, User, UserRole};
|
||||
use crate::utils::render_template;
|
||||
use jsonwebtoken::{encode, Header, EncodingKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{Utc, Duration};
|
||||
use actix_session::Session;
|
||||
use actix_web::{cookie::Cookie, http::header, web, HttpResponse, Responder, Result};
|
||||
use chrono::{Duration, Utc};
|
||||
use jsonwebtoken::{encode, EncodingKey, Header};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
use tera::Tera;
|
||||
|
||||
// JWT Claims structure
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
@ -19,7 +20,8 @@ pub struct Claims {
|
||||
|
||||
// JWT Secret key
|
||||
lazy_static! {
|
||||
static ref JWT_SECRET: String = std::env::var("JWT_SECRET").unwrap_or_else(|_| "your_jwt_secret_key".to_string());
|
||||
static ref JWT_SECRET: String =
|
||||
std::env::var("JWT_SECRET").unwrap_or_else(|_| "your_jwt_secret_key".to_string());
|
||||
}
|
||||
|
||||
/// Controller for handling authentication-related routes
|
||||
@ -27,7 +29,10 @@ pub struct AuthController;
|
||||
|
||||
impl AuthController {
|
||||
/// Generate a JWT token for a user
|
||||
pub fn generate_token(email: &str, role: &UserRole) -> Result<String, jsonwebtoken::errors::Error> {
|
||||
pub fn generate_token(
|
||||
email: &str,
|
||||
role: &UserRole,
|
||||
) -> Result<String, jsonwebtoken::errors::Error> {
|
||||
let role_str = match role {
|
||||
UserRole::Admin => "admin",
|
||||
UserRole::User => "user",
|
||||
@ -48,7 +53,7 @@ impl AuthController {
|
||||
encode(
|
||||
&Header::default(),
|
||||
&claims,
|
||||
&EncodingKey::from_secret(JWT_SECRET.as_bytes())
|
||||
&EncodingKey::from_secret(JWT_SECRET.as_bytes()),
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,8 +66,12 @@ impl AuthController {
|
||||
/// Renders the login page
|
||||
pub async fn login_page(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let mut ctx = tera::Context::new();
|
||||
let is_gitea_flow_active = env::var("GITEA_CLIENT_ID")
|
||||
.ok()
|
||||
.filter(|s| !s.is_empty())
|
||||
.is_some();
|
||||
ctx.insert("gitea_enabled", &is_gitea_flow_active);
|
||||
ctx.insert("active_page", "login");
|
||||
|
||||
// Add user to context if available
|
||||
if let Ok(Some(user_json)) = session.get::<String>("user") {
|
||||
// Keep the raw JSON for backward compatibility
|
||||
@ -73,7 +82,7 @@ impl AuthController {
|
||||
Ok(user) => {
|
||||
log::info!("Successfully parsed user in login_page: {:?}", user);
|
||||
ctx.insert("user", &user);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to parse user JSON in login_page: {}", e);
|
||||
log::error!("User JSON: {}", user_json);
|
||||
@ -88,14 +97,11 @@ impl AuthController {
|
||||
pub async fn login(
|
||||
form: web::Form<LoginCredentials>,
|
||||
session: Session,
|
||||
_tmpl: web::Data<Tera>
|
||||
_tmpl: web::Data<Tera>,
|
||||
) -> Result<impl Responder> {
|
||||
// For simplicity, always log in the user without checking credentials
|
||||
// Create a user object with admin role
|
||||
let mut test_user = User::new(
|
||||
"Admin User".to_string(),
|
||||
form.email.clone()
|
||||
);
|
||||
let mut test_user = User::new("Admin User".to_string(), form.email.clone());
|
||||
|
||||
// Set the ID and admin role
|
||||
test_user.id = Some(1);
|
||||
@ -132,6 +138,12 @@ impl AuthController {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.insert("active_page", "register");
|
||||
|
||||
let is_gitea_flow_active = env::var("GITEA_CLIENT_ID")
|
||||
.ok()
|
||||
.filter(|s| !s.is_empty())
|
||||
.is_some();
|
||||
ctx.insert("gitea_enabled", &is_gitea_flow_active);
|
||||
|
||||
// Add user to context if available
|
||||
if let Ok(Some(user_json)) = session.get::<String>("user") {
|
||||
// Keep the raw JSON for backward compatibility
|
||||
@ -142,7 +154,7 @@ impl AuthController {
|
||||
Ok(user) => {
|
||||
log::info!("Successfully parsed user in register_page: {:?}", user);
|
||||
ctx.insert("user", &user);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to parse user JSON in register_page: {}", e);
|
||||
log::error!("User JSON: {}", user_json);
|
||||
@ -157,13 +169,10 @@ impl AuthController {
|
||||
pub async fn register(
|
||||
form: web::Form<RegistrationData>,
|
||||
session: Session,
|
||||
_tmpl: web::Data<Tera>
|
||||
_tmpl: web::Data<Tera>,
|
||||
) -> Result<impl Responder> {
|
||||
// Skip validation and always create an admin user
|
||||
let mut user = User::new(
|
||||
form.name.clone(),
|
||||
form.email.clone()
|
||||
);
|
||||
let mut user = User::new(form.name.clone(), form.email.clone());
|
||||
|
||||
// Set the ID and admin role
|
||||
user.id = Some(1);
|
||||
|
@ -1,21 +1,15 @@
|
||||
use actix_web::{web, HttpRequest, HttpResponse, Responder, Result, http::header, cookie::Cookie};
|
||||
use actix_session::Session;
|
||||
use oauth2::{AuthorizationCode, CsrfToken, Scope, TokenResponse};
|
||||
use reqwest::Client;
|
||||
use crate::config::oauth::GiteaOAuthConfig;
|
||||
use crate::models::user::{User, UserRole};
|
||||
use crate::controllers::auth::AuthController;
|
||||
|
||||
#[cfg(feature = "gitea")]
|
||||
use oauth2::{AuthorizationCode, CsrfToken, Scope, TokenResponse};
|
||||
#[cfg(feature = "gitea")]
|
||||
use reqwest::Client;
|
||||
#[cfg(feature = "gitea")]
|
||||
use crate::config::oauth::GiteaOAuthConfig;
|
||||
|
||||
|
||||
/// Controller for handling Gitea authentication
|
||||
#[cfg(feature = "gitea")]
|
||||
pub struct GiteaAuthController;
|
||||
|
||||
#[cfg(feature = "gitea")]
|
||||
impl GiteaAuthController {
|
||||
/// Initiate the OAuth flow
|
||||
pub async fn login(
|
||||
@ -166,14 +160,22 @@ impl GiteaAuthController {
|
||||
let client = Client::new();
|
||||
let user_info_url = format!("{}/api/v1/user", oauth_config.instance_url);
|
||||
|
||||
let gitea_user = client
|
||||
log::info!("Gitea instance URL from config: {}", oauth_config.instance_url);
|
||||
|
||||
let access_token_secret = token.access_token().secret();
|
||||
log::info!("Using access token for /api/v1/user: {}", access_token_secret);
|
||||
|
||||
let response = client
|
||||
.get(&user_info_url)
|
||||
.bearer_auth(token.access_token().secret())
|
||||
.bearer_auth(access_token_secret)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("API request error: {}", e)))?
|
||||
.json::<crate::config::oauth::GiteaUser>()
|
||||
.await
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("API request error: {}", e)))?;
|
||||
|
||||
let response_body = response.text().await.map_err(|e| actix_web::error::ErrorInternalServerError(format!("Failed to get response body: {}", e)))?;
|
||||
log::info!("Raw Gitea user info response: {}", response_body);
|
||||
|
||||
let gitea_user: crate::config::oauth::GiteaUser = serde_json::from_str(&response_body)
|
||||
.map_err(|e| actix_web::error::ErrorInternalServerError(format!("JSON parsing error: {}", e)))?;
|
||||
|
||||
// Create or update the user in your system
|
||||
@ -213,7 +215,6 @@ impl GiteaAuthController {
|
||||
}
|
||||
|
||||
/// Query parameters for the OAuth callback
|
||||
#[cfg(feature = "gitea")]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CallbackQuery {
|
||||
pub code: String,
|
||||
|
@ -2,6 +2,7 @@ use actix_web::{web, Result, Responder};
|
||||
use tera::Tera;
|
||||
use crate::utils::render_template;
|
||||
use actix_session::Session;
|
||||
use std::env;
|
||||
|
||||
/// Controller for handling home-related routes
|
||||
pub struct HomeController;
|
||||
@ -12,6 +13,12 @@ impl HomeController {
|
||||
let mut ctx = tera::Context::new();
|
||||
ctx.insert("active_page", "home");
|
||||
|
||||
let is_gitea_flow_active = env::var("GITEA_CLIENT_ID")
|
||||
.ok()
|
||||
.filter(|s| !s.is_empty())
|
||||
.is_some();
|
||||
ctx.insert("gitea_enabled", &is_gitea_flow_active);
|
||||
|
||||
// Add user to context if available
|
||||
if let Ok(Some(user_json)) = session.get::<String>("user") {
|
||||
// Keep the raw JSON for backward compatibility
|
||||
@ -36,6 +43,11 @@ impl HomeController {
|
||||
/// Renders the about page
|
||||
pub async fn about(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
||||
let mut ctx = tera::Context::new();
|
||||
let is_gitea_flow_active = env::var("GITEA_CLIENT_ID")
|
||||
.ok()
|
||||
.filter(|s| !s.is_empty())
|
||||
.is_some();
|
||||
ctx.insert("gitea_enabled", &is_gitea_flow_active);
|
||||
ctx.insert("active_page", "about");
|
||||
|
||||
// Add user to context if available
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Export controllers
|
||||
pub mod auth;
|
||||
pub mod debug;
|
||||
#[cfg(feature = "gitea")]
|
||||
pub mod gitea_auth;
|
||||
pub mod home;
|
||||
|
@ -1,14 +1,13 @@
|
||||
#[cfg(feature = "gitea")]
|
||||
use crate::config::oauth::GiteaOAuthConfig;
|
||||
use crate::controllers::auth::AuthController;
|
||||
use crate::controllers::debug::DebugController;
|
||||
#[cfg(feature = "gitea")]
|
||||
use crate::controllers::gitea_auth::GiteaAuthController;
|
||||
use crate::controllers::home::HomeController;
|
||||
use crate::middleware::JwtAuth;
|
||||
use crate::SESSION_KEY;
|
||||
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
||||
use actix_web::web;
|
||||
use std::env;
|
||||
|
||||
/// Configures all application routes
|
||||
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
@ -26,35 +25,44 @@ pub fn configure_routes(cfg: &mut web::ServiceConfig) {
|
||||
)
|
||||
.build();
|
||||
|
||||
let mut scope = web::scope("")
|
||||
.wrap(session_middleware)
|
||||
// Build the main scope with common routes
|
||||
let mut main_scope = web::scope("")
|
||||
.wrap(session_middleware) // Wrap with session middleware
|
||||
// Home routes
|
||||
.route("/", web::get().to(HomeController::index))
|
||||
.route("/about", web::get().to(HomeController::about))
|
||||
// Auth routes
|
||||
.route("/login", web::get().to(AuthController::login_page))
|
||||
.route("/login", web::post().to(AuthController::login))
|
||||
.route("/register", web::get().to(AuthController::register_page))
|
||||
.route("/register", web::post().to(AuthController::register))
|
||||
.route("/logout", web::get().to(AuthController::logout))
|
||||
// Debug routes
|
||||
.route("/debug", web::get().to(DebugController::debug_info));
|
||||
.route("/about", web::get().to(HomeController::about));
|
||||
|
||||
#[cfg(feature = "gitea")]
|
||||
{
|
||||
// Create the OAuth configuration
|
||||
// Conditionally add authentication routes based on GITEA_CLIENT_ID environment variable
|
||||
if env::var("GITEA_CLIENT_ID").ok().filter(|s| !s.is_empty()).is_some() {
|
||||
// Use Gitea OAuth flow
|
||||
// Create the OAuth configuration and add it to the scope
|
||||
let oauth_config = web::Data::new(GiteaOAuthConfig::new());
|
||||
// Gitea OAuth configuration and routes
|
||||
scope = scope
|
||||
.app_data(oauth_config.clone())
|
||||
main_scope = main_scope
|
||||
.app_data(oauth_config) // Add oauth_config data
|
||||
// Gitea OAuth routes
|
||||
.route("/login", web::get().to(GiteaAuthController::login)) // Add /login route for gitea
|
||||
.route("/auth/gitea", web::get().to(GiteaAuthController::login))
|
||||
.route(
|
||||
"/auth/gitea/callback",
|
||||
web::get().to(GiteaAuthController::callback),
|
||||
);
|
||||
} else {
|
||||
// Use standard username/password login
|
||||
main_scope = main_scope
|
||||
.route("/login", web::get().to(AuthController::login_page))
|
||||
.route("/login", web::post().to(AuthController::login))
|
||||
.route("/register", web::get().to(AuthController::register_page))
|
||||
.route("/register", web::post().to(AuthController::register));
|
||||
}
|
||||
|
||||
cfg.service(scope);
|
||||
// Add common auth and debug routes (logout is common to both flows)
|
||||
main_scope = main_scope
|
||||
.route("/logout", web::get().to(AuthController::logout))
|
||||
// Debug routes
|
||||
.route("/debug", web::get().to(DebugController::debug_info));
|
||||
|
||||
// Register the main scope service
|
||||
cfg.service(main_scope);
|
||||
|
||||
// Protected routes that require authentication
|
||||
cfg.service(
|
||||
|
@ -1,8 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Login - Hostbasket{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% extends "base.html" %} {% block title %}Login - Hostbasket{% endblock %} {%
|
||||
block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
@ -11,39 +8,67 @@
|
||||
<h2>Login</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if not gitea_enabled %}
|
||||
<form method="post" action="/login">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
<label for="password" class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
{% if gitea_enabled %}
|
||||
<div class="text-center">
|
||||
<p>Or login with:</p>
|
||||
<a href="/auth/gitea" class="btn btn-secondary">
|
||||
<img src="/static/images/gitea-logo.svg" alt="Gitea" width="20" height="20"
|
||||
style="margin-right: 5px;">
|
||||
<img
|
||||
src="/static/images/gitea-logo.svg"
|
||||
alt="Gitea"
|
||||
width="20"
|
||||
height="20"
|
||||
style="margin-right: 5px"
|
||||
/>
|
||||
Login with Gitea
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
{% if not gitea_enabled %}
|
||||
<div class="text-center">
|
||||
<p>Don't have an account? <a href="/register">Register</a></p>
|
||||
<p>
|
||||
Don't have an account?
|
||||
<a href="/register">Register</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,4 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Register - Hostbasket{% endblock %}
|
||||
|
||||
{% extends "base.html" %} {% block title %}Register - Hostbasket{% endblock %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
@ -14,45 +11,65 @@
|
||||
<form method="post" action="/register">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
<label for="password" class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password_confirmation" class="form-label">Confirm Password</label>
|
||||
<input type="password" class="form-control" id="password_confirmation"
|
||||
name="password_confirmation" required>
|
||||
<label
|
||||
for="password_confirmation"
|
||||
class="form-label"
|
||||
>Confirm Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password_confirmation"
|
||||
name="password_confirmation"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Register</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Register
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
{% if gitea_enabled %}
|
||||
<div class="text-center">
|
||||
<p>Or register with:</p>
|
||||
<a href="/auth/gitea" class="btn btn-secondary">
|
||||
<img src="/static/images/gitea-logo.svg" alt="Gitea" width="20" height="20"
|
||||
style="margin-right: 5px;">
|
||||
Register with Gitea
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<div class="text-center">
|
||||
<p>Already have an account? <a href="/login">Login</a></p>
|
||||
<p>
|
||||
Already have an account? <a href="/login">Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -43,11 +43,13 @@
|
||||
<a class="nav-link {{ active_class(current=active_page, page=" login") }}"
|
||||
href="/login">Login</a>
|
||||
</li>
|
||||
{% if gitea_enabled == false %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ active_class(current=active_page, page=" register") }}"
|
||||
href="/register">Register</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,6 +63,7 @@
|
||||
<summary>Debug Info</summary>
|
||||
<pre>user_json: {{ user_json }}</pre>
|
||||
<pre>user object exists: {{ user is defined }}</pre>
|
||||
<pre>is_gitea_flow_active: {{ gitea_enabled }}</pre>
|
||||
{% if user is defined %}
|
||||
<pre>user.name: {{ user.name }}</pre>
|
||||
{% endif %}
|
||||
@ -81,4 +84,4 @@
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
4
start.sh
Normal file → Executable file
4
start.sh
Normal file → Executable file
@ -4,5 +4,7 @@
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
export SECRET_KEY=1234
|
||||
|
||||
export GITEA_CLIENT_ID=""
|
||||
export GITEA_CLIENT_SECRET=""
|
||||
export GITEA_INSTANCE_URL="https://git.ourworld.tf"
|
||||
cargo run
|
||||
|
@ -3,8 +3,8 @@
|
||||
# Get the directory of the script and change to it
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
export GITEA_CLIENT_ID="your_client_id"
|
||||
export GITEA_CLIENT_SECRET="your_client_secret"
|
||||
export GITEA_INSTANCE_URL="https://gitea.example.com"
|
||||
export GITEA_CLIENT_ID="9f409b35-6258-4ac3-8370-05adc187c1f5"
|
||||
export GITEA_CLIENT_SECRET="gto_4s77ae33m5ernlf2423wx6wjyyqatqoe567rym7fcu3sqmu5azea"
|
||||
export GITEA_INSTANCE_URL="https://git.ourworld.tf"
|
||||
export APP_URL="http://localhost:9999"
|
||||
cargo run --features gitea
|
||||
cargo run
|
||||
|
Loading…
Reference in New Issue
Block a user