Compare commits
4 Commits
8dec3e792a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f5e84523e | |||
|
|
fa12df8ec6 | ||
| 3b184488bb | |||
|
|
203e4bfb41 |
@@ -1,5 +1,5 @@
|
||||
# Logto auth endpoints — the marketing site only performs <a href> navigations to these.
|
||||
# No tokens, no cookies, no XHR — these are plain hyperlinks.
|
||||
PUBLIC_AUTH_SIGNIN_URL=https://auth.cameleer.io/sign-in
|
||||
PUBLIC_AUTH_SIGNUP_URL=https://auth.cameleer.io/sign-in?first_screen=register
|
||||
PUBLIC_AUTH_SIGNIN_URL=https://app.cameleer.io/sign-in
|
||||
PUBLIC_AUTH_SIGNUP_URL=https://app.cameleer.io/sign-in?first_screen=register
|
||||
PUBLIC_SALES_EMAIL=sales@cameleer.io
|
||||
|
||||
@@ -75,8 +75,8 @@ Add these under Repository settings → Actions → Secrets (or variables):
|
||||
| `SFTP_PATH` | secret | Absolute path to the Apache vhost docroot configured in konsoleH (typically `/usr/www/users/<login>/public_html`). Mismatch → 404 on origin. |
|
||||
| `SFTP_KEY` | secret | Contents of `~/.ssh/cameleer-website-deploy` (private key, PEM) |
|
||||
| `SFTP_KNOWN_HOSTS` | secret | Contents of `hetzner-known-hosts.txt` (captured via `ssh-keyscan`) |
|
||||
| `PUBLIC_AUTH_SIGNIN_URL` | secret | `https://auth.cameleer.io/sign-in` |
|
||||
| `PUBLIC_AUTH_SIGNUP_URL` | secret | `https://auth.cameleer.io/sign-in?first_screen=register` |
|
||||
| `PUBLIC_AUTH_SIGNIN_URL` | secret | `https://app.cameleer.io/sign-in` |
|
||||
| `PUBLIC_AUTH_SIGNUP_URL` | secret | `https://app.cameleer.io/sign-in?first_screen=register` |
|
||||
| `PUBLIC_SALES_EMAIL` | secret | `sales@cameleer.io` (or whatever sales alias you set up) |
|
||||
|
||||
These three are not actually secret (they end up in the built HTML), but Gitea's
|
||||
|
||||
@@ -5,7 +5,7 @@ const year = new Date().getFullYear();
|
||||
<div class="max-w-content mx-auto px-6 py-12 flex flex-col md:flex-row md:items-center md:justify-between gap-8">
|
||||
<div class="flex items-center gap-3">
|
||||
<img
|
||||
src="/cameleer-logo.svg"
|
||||
src="/icons/cameleer-32.png"
|
||||
width="24"
|
||||
height="24"
|
||||
alt=""
|
||||
|
||||
@@ -5,7 +5,7 @@ import CTAButtons from './CTAButtons.astro';
|
||||
<div class="max-w-content mx-auto px-6 h-16 flex items-center justify-between gap-6">
|
||||
<a href="/" class="flex items-center gap-2 group" aria-label="Cameleer home">
|
||||
<img
|
||||
src="/cameleer-logo.svg"
|
||||
src="/icons/cameleer-48.png"
|
||||
width="32"
|
||||
height="32"
|
||||
alt=""
|
||||
|
||||
@@ -22,7 +22,7 @@ const pins: Pin[] = [
|
||||
<div class="grid lg:grid-cols-12 gap-10 lg:gap-14 items-center">
|
||||
<div class="lg:col-span-5">
|
||||
<img
|
||||
src="/cameleer-logo.svg"
|
||||
src="/icons/cameleer-192.png"
|
||||
width="64"
|
||||
height="64"
|
||||
alt=""
|
||||
|
||||
@@ -4,57 +4,57 @@ import { resolveAuthConfig } from './auth';
|
||||
describe('resolveAuthConfig', () => {
|
||||
it('returns both URLs and sales email from env', () => {
|
||||
const cfg = resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
});
|
||||
expect(cfg.signInUrl).toBe('https://auth.cameleer.io/sign-in');
|
||||
expect(cfg.signUpUrl).toBe('https://auth.cameleer.io/sign-in?first_screen=register');
|
||||
expect(cfg.signInUrl).toBe('https://app.cameleer.io/sign-in');
|
||||
expect(cfg.signUpUrl).toBe('https://app.cameleer.io/sign-in?first_screen=register');
|
||||
expect(cfg.salesEmail).toBe('sales@cameleer.io');
|
||||
});
|
||||
|
||||
it('throws if PUBLIC_AUTH_SIGNIN_URL is missing', () => {
|
||||
expect(() => resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
})).toThrow(/PUBLIC_AUTH_SIGNIN_URL/);
|
||||
});
|
||||
|
||||
it('throws if a URL is not https', () => {
|
||||
expect(() => resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'http://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'http://app.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
})).toThrow(/must be https/);
|
||||
});
|
||||
|
||||
it('throws if sales email is not a valid mailto target', () => {
|
||||
expect(() => resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'not-an-email',
|
||||
})).toThrow(/PUBLIC_SALES_EMAIL/);
|
||||
});
|
||||
|
||||
it('throws if PUBLIC_AUTH_SIGNUP_URL is missing', () => {
|
||||
expect(() => resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
})).toThrow(/PUBLIC_AUTH_SIGNUP_URL/);
|
||||
});
|
||||
|
||||
it('throws if PUBLIC_AUTH_SIGNUP_URL is not https', () => {
|
||||
expect(() => resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'http://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'http://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
})).toThrow(/must be https/);
|
||||
});
|
||||
|
||||
it('exposes signUpUrl distinct from signInUrl', () => {
|
||||
const cfg = resolveAuthConfig({
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://auth.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://auth.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_AUTH_SIGNIN_URL: 'https://app.cameleer.io/sign-in',
|
||||
PUBLIC_AUTH_SIGNUP_URL: 'https://app.cameleer.io/sign-in?first_screen=register',
|
||||
PUBLIC_SALES_EMAIL: 'sales@cameleer.io',
|
||||
});
|
||||
expect(cfg.signUpUrl).not.toBe(cfg.signInUrl);
|
||||
|
||||
@@ -31,7 +31,6 @@ const ogUrl = new URL(ogImage, Astro.site ?? 'https://www.cameleer.io').toString
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={canonical} />
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="/cameleer-logo.svg" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/icons/cameleer-32.png" />
|
||||
<link rel="apple-touch-icon" href="/icons/cameleer-180.png" />
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export function buildSecurityHeaders(): Record<string, string> {
|
||||
"connect-src 'self'",
|
||||
"frame-ancestors 'none'",
|
||||
"base-uri 'self'",
|
||||
// No forms on this marketing site today (all auth redirects go to auth.cameleer.io
|
||||
// No forms on this marketing site today (all auth redirects go to app.cameleer.io
|
||||
// as plain <a> navigations). If a future form is added, relax to 'self' or an allow-list.
|
||||
"form-action 'none'",
|
||||
"object-src 'none'",
|
||||
|
||||
@@ -67,7 +67,7 @@ const lastUpdated = '2026-04-24';
|
||||
<section class="mb-10">
|
||||
<h2 class="text-lg font-bold text-text mb-3">6. External links</h2>
|
||||
<p class="text-text-muted leading-relaxed">
|
||||
Sign-in and sign-up links on this site navigate you to <span class="font-mono text-accent">auth.cameleer.io</span> (Logto identity service) and subsequently <span class="font-mono text-accent">platform.cameleer.io</span>. Those services have their own privacy policies, which apply from the moment you arrive there.
|
||||
Sign-in and sign-up links on this site navigate you to <span class="font-mono text-accent">app.cameleer.io</span> (the Cameleer app, where authentication is handled by Logto). That service has its own privacy policy, which applies from the moment you arrive there.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user