Implement Auth0, + templates.
This commit is contained in:
@@ -7,9 +7,14 @@ services:
|
|||||||
- "80"
|
- "80"
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
- ConnectionStrings__DefaultConnection=Server=sqlserver;Database=Printbase;User Id=sa;Password=YourStrong(!)Password;Encrypt=false;TrustServerCertificate=true;MultipleActiveResultSets=true;
|
- ConnectionStrings__DefaultConnection=Server=${SQL_SERVER};Database=${SQL_DATABASE};User Id=${SQL_USER_ID};Password=${SQL_PASSWORD};Encrypt=false;TrustServerCertificate=true;MultipleActiveResultSets=true;
|
||||||
|
- ASPNETCORE_URLS=http://+:8080
|
||||||
|
- Auth0__Domain=${AUTH0_ISSUER_BASE_URL}
|
||||||
|
- Auth0__Audience=${AUTH0_AUDIENCE}
|
||||||
depends_on:
|
depends_on:
|
||||||
- mssql
|
- mssql
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
webui:
|
webui:
|
||||||
image: node:18-alpine
|
image: node:18-alpine
|
||||||
@@ -20,7 +25,19 @@ services:
|
|||||||
- "3000"
|
- "3000"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
- NODE_ENV=development
|
||||||
|
- AUTH0_SECRET=${AUTH0_SECRET}
|
||||||
|
- APP_BASE_URL=${APP_BASE_URL}
|
||||||
|
- AUTH0_DOMAIN=${AUTH0_ISSUER_BASE_URL}
|
||||||
|
- AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}
|
||||||
|
- AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET}
|
||||||
|
- AUTH0_AUDIENCE=${AUTH0_AUDIENCE}
|
||||||
|
- AUTH0_SCOPE=openid profile email read:shows
|
||||||
|
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||||
|
- NEXT_PUBLIC_AUTH0_CLIENT_ID=${NEXT_PUBLIC_AUTH0_CLIENT_ID}
|
||||||
|
- NEXT_PUBLIC_AUTH0_DOMAIN=${NEXT_PUBLIC_AUTH0_DOMAIN}
|
||||||
command: "sh -c 'npm install && npm run dev'"
|
command: "sh -c 'npm install && npm run dev'"
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
mssql:
|
mssql:
|
||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
@@ -28,16 +45,27 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "1433:1433"
|
- "1433:1433"
|
||||||
environment:
|
environment:
|
||||||
SA_PASSWORD: "YourStrong(!)Password"
|
SA_PASSWORD: "${SQL_PASSWORD}"
|
||||||
ACCEPT_EULA: "Y"
|
ACCEPT_EULA: "Y"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:latest
|
image: nginx:latest
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./ssl/impr.ink-chain.pem:/etc/ssl/certs/impr.ink.crt:ro
|
||||||
|
- ./ssl/impr.ink-key.pem:/etc/ssl/private/impr.ink.key:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- webapi
|
- webapi
|
||||||
- webui
|
- webui
|
||||||
|
networks:
|
||||||
|
- app-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
app-network:
|
||||||
|
driver: bridge
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
events {}
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_buffers 4 16k;
|
||||||
|
proxy_busy_buffers_size 16k;
|
||||||
|
|
||||||
|
large_client_header_buffers 4 16k;
|
||||||
|
|
||||||
upstream webapi {
|
upstream webapi {
|
||||||
server webapi:8080;
|
server webapi:8080;
|
||||||
}
|
}
|
||||||
@@ -11,6 +19,24 @@ http {
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
server_name impr.ink;
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name impr.ink;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/certs/impr.ink.crt;
|
||||||
|
ssl_certificate_key /etc/ssl/private/impr.ink.key;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options DENY always;
|
||||||
|
add_header X-Content-Type-Options nosniff always;
|
||||||
|
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://webapi/;
|
proxy_pass http://webapi/;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MediatR" Version="12.5.0" />
|
<PackageReference Include="MediatR" Version="12.5.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
using Imprink.Application;
|
using Imprink.Application;
|
||||||
using Imprink.Application.Products.Handlers;
|
using Imprink.Application.Products.Handlers;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Infrastructure;
|
using Imprink.Infrastructure;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
using Imprink.Infrastructure.Repositories;
|
using Imprink.Infrastructure.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
namespace Imprink.WebApi;
|
namespace Imprink.WebApi;
|
||||||
|
|
||||||
@@ -28,6 +31,19 @@ public static class Startup
|
|||||||
{
|
{
|
||||||
cfg.RegisterServicesFromAssembly(typeof(CreateProductHandler).Assembly);
|
cfg.RegisterServicesFromAssembly(typeof(CreateProductHandler).Assembly);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = $"https://{builder.Configuration["Auth0:Domain"]}/";
|
||||||
|
options.Audience = builder.Configuration["Auth0:Audience"];
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
NameClaimType = ClaimTypes.NameIdentifier
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddSwaggerGen();
|
services.AddSwaggerGen();
|
||||||
|
|||||||
759
webui/auth0-templates/login.html
Normal file
759
webui/auth0-templates/login.html
Normal file
@@ -0,0 +1,759 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<link rel="icon" href="https://i.ibb.co/gbthcbnP/logo-sm.png" type="image/png" />
|
||||||
|
<title>Sign In | Imprink</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||||
|
<link href="https://fonts.cdnfonts.com/css/scanno-hanley-pro-sans" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
background-image: url('https://i.ibb.co/BDSg5pD/vecteezy-abstract-arrows-ribbons-crowns-hearts-explosions-and-5891677.jpg');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
position: relative;
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
background: linear-gradient(135deg,
|
||||||
|
rgba(108, 92, 231, 0.4),
|
||||||
|
rgba(0, 184, 148, 0.4)
|
||||||
|
);
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invisible {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 0 5%;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
gap: clamp(20px, 5vw, 150px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-section {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
animation: slideLeft 1s ease-out;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-section img {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-section {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
animation: slideRight 1s ease-out;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1),
|
||||||
|
0 2px 8px rgba(0, 0, 0, 0.05),
|
||||||
|
inset 0 1px 1px rgba(255, 255, 255, 0.1),
|
||||||
|
0 0 20px rgba(108, 92, 231, 0.2),
|
||||||
|
0 0 40px rgba(0, 184, 148, 0.1);
|
||||||
|
border-radius: 20px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 360px;
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
animation: fadeIn 0.5s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header h3 {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
font-size: 28px;
|
||||||
|
color: #2d3436;
|
||||||
|
margin: 15px 0 5px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header h5 {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #636e72;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header img {
|
||||||
|
width: 80%;
|
||||||
|
animation: slideIn 0.8s ease-out forwards;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header .mobile-logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error-message {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
display: none;
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
#success-message {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
display: none;
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
margin: 25px 0;
|
||||||
|
color: #636e72;
|
||||||
|
font-size: 13px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider::before,
|
||||||
|
.divider::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider::before {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider::after {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-btn {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
background: white;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-btn img {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-btn:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-google:hover {
|
||||||
|
background: #DB4437;
|
||||||
|
border-color: #DB4437;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-github:hover {
|
||||||
|
background: #333;
|
||||||
|
border-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-facebook:hover {
|
||||||
|
background: #4267B2;
|
||||||
|
border-color: #4267B2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-linkedin:hover {
|
||||||
|
background: #0077B5;
|
||||||
|
border-color: #0077B5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-windows:hover {
|
||||||
|
background: #00A4EF;
|
||||||
|
border-color: #00A4EF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#link-signup-login {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #6c5ce7;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#link-signup-login:hover {
|
||||||
|
color: #5f4dd0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-signup {
|
||||||
|
background-color: #00b894;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-signup:hover {
|
||||||
|
background-color: #00a884;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 184, 148, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
height: 40px;
|
||||||
|
border: 1.5px solid rgba(0, 0, 0, 0.08);
|
||||||
|
border-radius: 12px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #2d3436;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: #6c5ce7;
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control::placeholder {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
color: #b2bec3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #2d3436;
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 14px;
|
||||||
|
height: auto;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #6c5ce7;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #5f4dd0;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(108, 92, 231, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideLeft {
|
||||||
|
0% {
|
||||||
|
transform: translateX(50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideRight {
|
||||||
|
0% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.login-container {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-section {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-section {
|
||||||
|
width: 100%;
|
||||||
|
animation: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
animation: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header .mobile-logo {
|
||||||
|
display: block;
|
||||||
|
width: 80%;
|
||||||
|
margin: 0 auto 20px auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
0% {
|
||||||
|
transform: translateY(50px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password {
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a {
|
||||||
|
font-family: 'Scanno Hanley Pro Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
color: #6c5ce7;
|
||||||
|
font-size: 13px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password a:hover {
|
||||||
|
color: #5f4dd0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="logo-section">
|
||||||
|
<img src="https://i.ibb.co/0RK5CM5Q/logo-light.png" class="img-fluid"/>
|
||||||
|
</div>
|
||||||
|
<div class="login-section">
|
||||||
|
<div class="login-box">
|
||||||
|
<div class="login-header">
|
||||||
|
<img src="https://i.ibb.co/0RK5CM5Q/logo-light.png" class="img-fluid mobile-logo"/>
|
||||||
|
<h3>Welcome</h3>
|
||||||
|
<h5>PLEASE LOG IN</h5>
|
||||||
|
</div>
|
||||||
|
<div id="error-message" class="alert alert-danger"></div>
|
||||||
|
<div id="success-message" class="alert alert-success"></div>
|
||||||
|
<form onsubmit="return false;" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Email</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
class="form-control"
|
||||||
|
id="email"
|
||||||
|
placeholder="Enter your email">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control"
|
||||||
|
id="password"
|
||||||
|
placeholder="Enter your password">
|
||||||
|
<div class="forgot-password">
|
||||||
|
<a href="#" id="forgot-password-link">Forgot your password?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="captcha-container form-group"></div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
id="btn-login"
|
||||||
|
class="btn btn-primary btn-block">
|
||||||
|
Log In
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-signup"
|
||||||
|
class="btn btn-default btn-block invisible">
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
<div class="divider" id="divider">or continue with</div>
|
||||||
|
<div class="social-buttons" id="social-buttons">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-google"
|
||||||
|
class="social-btn btn-google"
|
||||||
|
title="Sign in with Google">
|
||||||
|
<img src="https://cdn4.iconfinder.com/data/icons/logos-brands-7/512/google_logo-google_icongoogle-512.png" alt="Google">
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-github"
|
||||||
|
class="social-btn btn-github"
|
||||||
|
title="Sign in with GitHub">
|
||||||
|
<img src="https://img.icons8.com/m_outlined/512/github.png" alt="GitHub">
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-facebook"
|
||||||
|
class="social-btn btn-facebook"
|
||||||
|
title="Sign in with Facebook">
|
||||||
|
<img src="https://www.freeiconspng.com/uploads/facebook-png-icon-follow-us-facebook-1.png" alt="Facebook">
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-linkedin"
|
||||||
|
class="social-btn btn-linkedin"
|
||||||
|
title="Sign in with LinkedIn">
|
||||||
|
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/LinkedIn_icon.svg/1024px-LinkedIn_icon.svg.png" alt="LinkedIn">
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
id="btn-windows"
|
||||||
|
class="social-btn btn-windows"
|
||||||
|
title="Sign in with Microsoft">
|
||||||
|
<img src="https://cdn-icons-png.freepik.com/256/11378/11378754.png?semt=ais_hybrid" alt="Microsoft">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="form-group">
|
||||||
|
<span id="login-signup-msg">Don't have an account?</span> <a id="link-signup-login"> Sign Up </a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--[if IE 8]>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<!--[if lte IE 9]>
|
||||||
|
<script src="https://cdn.auth0.com/js/polyfills/1.0/base64.min.js"></script>
|
||||||
|
<script src="https://cdn.auth0.com/js/polyfills/1.0/es5-shim.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<script src="https://cdn.auth0.com/js/auth0/9.28/auth0.min.js"></script>
|
||||||
|
<script src="https://cdn.auth0.com/js/polyfills/1.0/object-assign.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function capitalizeFirstLetter(str) {
|
||||||
|
if (!str) return '';
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
|
||||||
|
var config = JSON.parse(
|
||||||
|
decodeURIComponent(escape(window.atob('@@config@@')))
|
||||||
|
);
|
||||||
|
|
||||||
|
var leeway = config.internalOptions.leeway;
|
||||||
|
if (leeway) {
|
||||||
|
var convertedLeeway = parseInt(leeway);
|
||||||
|
|
||||||
|
if (!isNaN(convertedLeeway)) {
|
||||||
|
config.internalOptions.leeway = convertedLeeway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
overrides: {
|
||||||
|
__tenant: config.auth0Tenant,
|
||||||
|
__token_issuer: config.authorizationServer.issuer
|
||||||
|
},
|
||||||
|
domain: config.auth0Domain,
|
||||||
|
clientID: config.clientID,
|
||||||
|
redirectUri: config.callbackURL,
|
||||||
|
responseType: 'code',
|
||||||
|
scope: config.internalOptions.scope,
|
||||||
|
_csrf: config.internalOptions._csrf,
|
||||||
|
state: config.internalOptions.state,
|
||||||
|
_intstate: config.internalOptions._intstate
|
||||||
|
};
|
||||||
|
|
||||||
|
var triggerCaptcha = null;
|
||||||
|
var signupCaptcha = null;
|
||||||
|
var webAuth = new auth0.WebAuth(params);
|
||||||
|
var databaseConnection = 'Username-Password-Authentication';
|
||||||
|
var captcha = webAuth.renderCaptcha(
|
||||||
|
document.querySelector('.captcha-container'),
|
||||||
|
null,
|
||||||
|
(error, payload) => {
|
||||||
|
if (payload) {
|
||||||
|
triggerCaptcha = payload.triggerCaptcha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function login(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var button = this;
|
||||||
|
var username = document.getElementById('email').value;
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
button.disabled = true;
|
||||||
|
|
||||||
|
var request = () => {
|
||||||
|
webAuth.login({
|
||||||
|
realm: databaseConnection,
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
captcha: captcha.getValue()
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
button.disabled = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (triggerCaptcha) {
|
||||||
|
triggerCaptcha(request);
|
||||||
|
} else {
|
||||||
|
request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSignupLogin(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var loginSignupLink = e.target;
|
||||||
|
var loginBtn = document.getElementById('btn-login');
|
||||||
|
var signupBtn = document.getElementById('btn-signup');
|
||||||
|
var msg = document.getElementById('login-signup-msg');
|
||||||
|
var socialButtons = document.getElementById('social-buttons');
|
||||||
|
var divider = document.getElementById('divider');
|
||||||
|
|
||||||
|
loginBtn.classList.toggle('invisible');
|
||||||
|
signupBtn.classList.toggle('invisible');
|
||||||
|
socialButtons.classList.toggle('invisible');
|
||||||
|
divider.classList.toggle('invisible');
|
||||||
|
|
||||||
|
if (signupBtn.classList.contains('invisible')) {
|
||||||
|
loginSignupLink.innerHTML = "Sign Up";
|
||||||
|
msg.innerHTML = "Don't have an account?";
|
||||||
|
} else {
|
||||||
|
loginSignupLink.innerHTML = "Log In";
|
||||||
|
msg.innerHTML = "Already have an account?";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signupBtn.classList.contains('invisible')) {
|
||||||
|
captcha = webAuth.renderCaptcha(
|
||||||
|
document.querySelector('.captcha-container'),
|
||||||
|
null,
|
||||||
|
(error, payload) => {
|
||||||
|
if (payload) {
|
||||||
|
triggerCaptcha = payload.triggerCaptcha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
signupCaptcha = webAuth.renderSignupCaptcha(
|
||||||
|
document.querySelector('.captcha-container'),
|
||||||
|
null,
|
||||||
|
(error, payload) => {
|
||||||
|
if (payload) {
|
||||||
|
triggerCaptcha = payload.triggerCaptcha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function signup() {
|
||||||
|
var button = this;
|
||||||
|
var email = document.getElementById('email').value;
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
button.disabled = true;
|
||||||
|
|
||||||
|
var request = () => {
|
||||||
|
webAuth.redirect.signupAndLogin({
|
||||||
|
connection: databaseConnection,
|
||||||
|
email: email,
|
||||||
|
password: password,
|
||||||
|
captcha: signupCaptcha.getValue()
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
button.disabled = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (triggerCaptcha) {
|
||||||
|
triggerCaptcha(request);
|
||||||
|
} else {
|
||||||
|
request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginWithGoogle() {
|
||||||
|
webAuth.authorize({
|
||||||
|
connection: 'google-oauth2'
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginWithGithub() {
|
||||||
|
webAuth.authorize({
|
||||||
|
connection: 'github'
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginWithFacebook() {
|
||||||
|
webAuth.authorize({
|
||||||
|
connection: 'facebook'
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginWithLinkedIn() {
|
||||||
|
webAuth.authorize({
|
||||||
|
connection: 'linkedin'
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginWithWindows() {
|
||||||
|
webAuth.authorize({
|
||||||
|
connection: 'windowslive'
|
||||||
|
}, function(err) {
|
||||||
|
if (err) displayError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayError(err) {
|
||||||
|
captcha.reload();
|
||||||
|
var successMessage = document.getElementById('success-message');
|
||||||
|
successMessage.style.display = 'none';
|
||||||
|
var errorMessage = document.getElementById('error-message');
|
||||||
|
errorMessage.innerText = capitalizeFirstLetter(err.policy) || capitalizeFirstLetter(err.description);
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function displaySuccess(text) {
|
||||||
|
captcha.reload();
|
||||||
|
var errorMessage = document.getElementById('error-message');
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
var successMessage = document.getElementById('success-message');
|
||||||
|
successMessage.innerText = text;
|
||||||
|
successMessage.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function forgotPassword(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
var config = JSON.parse(
|
||||||
|
decodeURIComponent(escape(window.atob('@@config@@')))
|
||||||
|
);
|
||||||
|
|
||||||
|
webAuth.changePassword({
|
||||||
|
connection: databaseConnection,
|
||||||
|
email: document.getElementById('email').value
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error:', err);
|
||||||
|
displayError(err);
|
||||||
|
} else {
|
||||||
|
displaySuccess('Password reset email sent! Please check your inbox.');
|
||||||
|
console.log('Password reset email sent');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in forgot password:', error);
|
||||||
|
displayError({ description: 'Unable to process password reset request. Please try again.' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('btn-login').addEventListener('click', login);
|
||||||
|
document.getElementById('btn-google').addEventListener('click', loginWithGoogle);
|
||||||
|
document.getElementById('btn-github').addEventListener('click', loginWithGithub);
|
||||||
|
document.getElementById('btn-facebook').addEventListener('click', loginWithFacebook);
|
||||||
|
document.getElementById('btn-linkedin').addEventListener('click', loginWithLinkedIn);
|
||||||
|
document.getElementById('btn-windows').addEventListener('click', loginWithWindows);
|
||||||
|
document.getElementById('btn-signup').addEventListener('click', signup);
|
||||||
|
document.getElementById('link-signup-login').addEventListener('click', toggleSignupLogin);
|
||||||
|
document.getElementById('forgot-password-link').addEventListener('click', forgotPassword);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
86
webui/package-lock.json
generated
86
webui/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "webui",
|
"name": "webui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth0/nextjs-auth0": "^4.6.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
@@ -44,6 +45,33 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@auth0/nextjs-auth0": {
|
||||||
|
"version": "4.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.6.0.tgz",
|
||||||
|
"integrity": "sha512-HK+fcUW6P8/qUDQfOfntftMg6yzeZLtyfTxL/lyeOub1o/xTL9SZ2fF39nH0H6w1loB5SCAbyN1vD8xxBwINqQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@edge-runtime/cookies": "^5.0.1",
|
||||||
|
"@panva/hkdf": "^1.2.1",
|
||||||
|
"jose": "^5.9.6",
|
||||||
|
"oauth4webapi": "^3.1.2",
|
||||||
|
"swr": "^2.2.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"next": "^14.2.25 || ^15.2.3",
|
||||||
|
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-0",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@edge-runtime/cookies": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@edge-runtime/cookies/-/cookies-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sd8LcWpZk/SWEeKGE8LT6gMm5MGfX/wm+GPnh1eBEtCpya3vYqn37wYknwAHw92ONoyyREl1hJwxV/Qx2DWNOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
|
||||||
@@ -650,6 +678,15 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@panva/hkdf": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@swc/counter": {
|
"node_modules/@swc/counter": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||||
@@ -1033,6 +1070,15 @@
|
|||||||
"simple-swizzle": "^0.2.2"
|
"simple-swizzle": "^0.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dequal": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||||
@@ -1081,6 +1127,15 @@
|
|||||||
"jiti": "lib/jiti-cli.mjs"
|
"jiti": "lib/jiti-cli.mjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jose": {
|
||||||
|
"version": "5.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
|
||||||
|
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lightningcss": {
|
"node_modules/lightningcss": {
|
||||||
"version": "1.30.1",
|
"version": "1.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
|
||||||
@@ -1469,6 +1524,15 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/oauth4webapi": {
|
||||||
|
"version": "3.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.1.tgz",
|
||||||
|
"integrity": "sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/panva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
@@ -1636,6 +1700,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/swr": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dequal": "^2.0.3",
|
||||||
|
"use-sync-external-store": "^1.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.1.8",
|
"version": "4.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.8.tgz",
|
||||||
@@ -1677,6 +1754,15 @@
|
|||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
|
"node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||||
|
|||||||
@@ -9,9 +9,10 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth0/nextjs-auth0": "^4.6.0",
|
||||||
|
"next": "15.3.3",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0"
|
||||||
"next": "15.3.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
|||||||
@@ -3,101 +3,7 @@ import Image from "next/image";
|
|||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
<a href="/auth/login">Login</a>
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js logo"
|
|
||||||
width={180}
|
|
||||||
height={38}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
|
||||||
<li className="mb-2 tracking-[-.01em]">
|
|
||||||
Get started by editing{" "}
|
|
||||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
|
||||||
src/app/page.js
|
|
||||||
</code>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li className="tracking-[-.01em]">
|
|
||||||
Save and see your changes instantly.
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className="dark:invert"
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel logomark"
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
Deploy now
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Read our docs
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/file.svg"
|
|
||||||
alt="File icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Learn
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/window.svg"
|
|
||||||
alt="Window icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Examples
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/globe.svg"
|
|
||||||
alt="Globe icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Go to nextjs.org →
|
|
||||||
</a>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
8
webui/src/lib/auth0.js
Normal file
8
webui/src/lib/auth0.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Auth0Client } from "@auth0/nextjs-auth0/server";
|
||||||
|
|
||||||
|
export const auth0 = new Auth0Client({
|
||||||
|
authorizationParameters: {
|
||||||
|
scope: 'openid profile email read:shows',
|
||||||
|
audience: 'imprink-front'
|
||||||
|
}
|
||||||
|
});
|
||||||
11
webui/src/middleware.js
Normal file
11
webui/src/middleware.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { auth0 } from "./lib/auth0";
|
||||||
|
|
||||||
|
export async function middleware(request) {
|
||||||
|
return await auth0.middleware(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
||||||
|
],
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user