Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
loan-mgt committed Sep 15, 2024
1 parent 1f91053 commit b8a0404
Show file tree
Hide file tree
Showing 8 changed files with 491 additions and 273 deletions.
65 changes: 64 additions & 1 deletion handlers/your-cal.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import (
)

// generateICSHandler generates the ICS file and sends it in the response with a given filename
func GenerateICSHandler(w http.ResponseWriter, r *http.Request, filename, calendarName string) {
func GenerateICSHandler(w http.ResponseWriter, r *http.Request) {
// Get start and end times from environment variables
start := os.Getenv("START_TIMESTAMP")
end := os.Getenv("END_TIMESTAMP")

// Get separator from environment variable
separator := os.Getenv("SEPARATOR")

filename := "cpe-calendar" + ".ics"

calendarName := "CPE Calendar"

// Get query param 'creds'
cryptedCreds := r.URL.Query().Get("creds")

Expand Down Expand Up @@ -69,3 +73,62 @@ func GenerateICSHandler(w http.ResponseWriter, r *http.Request, filename, calend
// Write the iCal content to the response
w.Write([]byte(icsContent))
}

func ValidateHandler(w http.ResponseWriter, r *http.Request) {
// Get start and end times from environment variables
start := os.Getenv("START_TIMESTAMP")
end := os.Getenv("END_TIMESTAMP")

// Get separator from environment variable
separator := os.Getenv("SEPARATOR")

// Get query param 'creds'
cryptedCreds := r.URL.Query().Get("creds")

// Load the RSA private key
privateKey, err := decrypt.LoadPrivateKey()
if err != nil {
log.Printf("Error loading private key: %v", err)
http.Error(w, "Failed to load private key", http.StatusInternalServerError)
return
}

// Decrypt the message
decryptedMessage, err := decrypt.DecryptMessage(cryptedCreds, privateKey)
if err != nil {
log.Printf("Error decrypting message: %v", err)
http.Error(w, "Invalid credentials", http.StatusBadRequest)
return
}

// Split the decrypted message using the separator
parts := strings.Split(decryptedMessage, separator)
if len(parts) < 2 {
http.Error(w, "Invalid credentials format", http.StatusBadRequest)
return
}
username := parts[0]
pass := parts[1]

// Fetch data from the source
data, err := request.FetchData(start, end, username, pass)
if err != nil {
log.Printf("Failed to fetch data: %v", err)
http.Error(w, "Failed to fetch data", http.StatusInternalServerError)
return
}

// Parse the fetched data
events, err := ical.ParseEvents(data)
if err != nil {
log.Printf("Failed to parse events: %v", err)
http.Error(w, "Failed to parse events", http.StatusInternalServerError)
return
}

if len(events) > 0 {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusUnauthorized)
}
}
11 changes: 4 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ func main() {
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))

// Serve calendar.ics route
r.HandleFunc("/your-cpe-calendar.ics", generate3IRCHandler).Methods("GET")
r.HandleFunc("/your-cpe-calendar.ics", handlers.GenerateICSHandler).Methods("GET")

//validate route
r.HandleFunc("/validate", handlers.ValidateHandler).Methods("POST")

// Use the router in the http server
log.Fatal(http.ListenAndServe(":8080", r))
Expand All @@ -56,9 +59,3 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Error rendering template", http.StatusInternalServerError)
}
}

// generate3IRCHandler is a wrapper around generateICSHandler that uses a specific filename
func generate3IRCHandler(w http.ResponseWriter, r *http.Request) {
// Call generateICSHandler with the specific filename and calendar name
handlers.GenerateICSHandler(w, r, "3irc_calendar.ics", "3IRC Calendar")
}
23 changes: 0 additions & 23 deletions static/encryption.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@

function copyLink(link) {
const fullLink = `${window.location.origin}${link}`;
navigator.clipboard.writeText(fullLink).then(() => {
showToast();
}).catch(err => {
console.error('Failed to copy text: ', err);
});
}

/*
The unwrapped signing key.
*/
Expand Down Expand Up @@ -100,16 +90,3 @@ async function encryptMessage(message) {
// Convert the ciphertext to Base64
return arrayBufferToBase64(ciphertext);
}


function showToast() {
const toast = document.getElementById('toast');
toast.className = 'show';
setTimeout(() => {
toast.className = toast.className.replace('show', '');
}, 3000);
}

importPublicKey(pemEncodedKey).then(key => {
encryptionKey = key;
});
Binary file added static/fonts/BricolageGrotesque-Bold.woff2
Binary file not shown.
186 changes: 128 additions & 58 deletions static/index.html
Original file line number Diff line number Diff line change
@@ -1,83 +1,153 @@
<!DOCTYPE html>
<html lang="en">
<html lang="fr">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CPE Calendar</title>
<meta name="description" content="Sync your CPE calendar with your personal one">
<meta name="keywords" content="calendar, ics, CPE, apple, google">
<title>Calendrier CPE</title>
<meta name="description" content="Synchronisez votre calendrier CPE avec votre calendrier personnel">
<meta name="keywords" content="calendrier, ics, CPE, apple, google">
<meta name="author" content="https://github.com/loan-mgt">
<meta property="og:title" content="CPE Calendar">
<meta property="og:description" content="Sync your CPE calendar with your personal one">
<meta property="og:title" content="Calendrier CPE">
<meta property="og:description" content="Synchronisez votre calendrier CPE avec votre calendrier personnel">
<meta property="og:image" content="/static/banner.png">
<meta property="og:url" content="https://cpe-cal.for-loop.fr">
<meta property="og:type" content="website">
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap" rel="stylesheet">

<link rel="stylesheet" href="/static/style.css">
<link rel="stylesheet" href="/static/styles.css">
</head>

<body>
<div class="core">
<header>
<h1>CPE Calendar</h1>
</header>
<main>
<div id="calendar">
<h2>The best way to stay up-to-date with your schedule using your personal calendar app.</h2>
<a href="#available">Let's get started</a>
</div>
</main>
</div>

<div class="list">
<div class="center">
<h2 id="available">Get your calendars</h2>
</div>
<ul>
<li>
<label>Enter your CPE credentials to generate a calendar</label>
<div>
<input type="text" id="username" placeholder="Email" />
<input type="password" id="password" placeholder="Password" />
<header>
<nav>
<ul>
<img src="/static/logo.svg">
<li><a href="#about">À propos</a></li>
<li><a href="#trust">Confiance</a></li>
<li><a href="#affiliation">Affiliation</a></li>
</ul>
<ul>
<li><a href="https://github.com/loan-mgt/cpe-calendar">Code Source</a></li>
<li><a class="btn-secondary" href="#get-calendar">Obtenir l'URL</a></li>
</ul>
</nav>
</header>

<main>
<section class="hero">
<h1>Synchronisez votre calendrier CPE avec votre téléphone</h1>
<p>Restez informé de tout changement de plan sans effort et accédez facilement à votre prochain lieu de
rendez-vous.</p>
<a href="#get-calendar" class="btn-hero">
<img src="/static/logo.svg">
<span>Obtenez votre calendrier</span></a>
</section>

<section id="get-calendar" class="get-calendar">
<h2>Obtenez votre calendrier</h2>
<form>
<div class="form-row">
<label for="email">Email CPE</label>
<input type="email" id="email" name="email" placeholder="Votre email CPE" required>
</div>
<button onclick="generateEncryptedLink()">Generate Calendar Link</button>
</li>
</ul>
</div>
<div class="form-row">
<label for="password">Mot de passe</label>
<input type="password" id="password" name="password" placeholder="Votre mot de passe CPE" required>
</div>
<button class="btn-primary" onclick="generateEncryptedLink()">Obtenez votre calendrier</button>
</form>
</section>

<div id="toast">Link copied to clipboard!</div>
<section id="about" class="about">
<h2>À propos</h2>
<p>L'objectif du Calendrier CPE est d'offrir à chaque étudiant un accès simple et sans effort à leur
calendrier en connectant leur calendrier scolaire à leur calendrier personnel. Cela fonctionne sur tous
les appareils—téléphone, ordinateur portable—et avec n'importe quel fournisseur, y compris Apple et
Android.</p>
<p>Le calendrier se mettra automatiquement à jour sur votre appareil toutes les heures, vous permettant de
rester informé de tout changement d'emploi du temps.</p>
<p>Ce projet est open-source. Si à tout moment vous constatez un problème ou une fonctionnalité manquante,
n'hésitez pas à nous contacter et à partager cela sur GitHub.</p>
</section>

<section id="trust" class="trust">
<h2>Confiance</h2>
<p>Comme pour tous les projets open-source hébergés, il n'y a aucune garantie que le propriétaire de
l'instance n'ait pas altéré le code officiel. Cela signifie qu'il y aura toujours un certain niveau de
confiance impliqué dans la chaîne.</p>
<p>Voici quelques recommandations et bonnes pratiques en fonction de votre niveau de confiance ou du risque
que vous êtes prêt à accepter :</p>
<ol>
<li>Pleine confiance : Utilisez le service tel quel.</li>
<li>Quelques doutes : Limitez l'impact des problèmes potentiels en prenant des précautions, comme créer
un mot de passe dédié pour le service.</li>
<li>Aucun risque : Comme il s'agit d'un projet open-source, vous pouvez héberger votre propre instance.
Un guide est disponible ici.</li>
</ol>
</section>

<script>
const pemEncodedKey = `{{.PublicKey}}`;
const separator = `{{.Separator}}`;
<section id="affiliation" class="affiliation">
<h2>Affiliation</h2>
<p>Ce projet est entièrement indépendant et n'est affilié à aucune école ou organisation.</p>
</section>
</main>

async function generateEncryptedLink() {
try {
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
<footer>
<div>
<p>Calendrier 3 16 5 | 2024</p>
<a class="btn-secondary" href="https://github.com/loan-mgt/cpe-calendar">Code Source</a>
</div>
</footer>
<div id="toast">Link copied to clipboard!</div>
<script src="/static/encryption.js"></script>
<script >
const pemEncodedKey = `{{.PublicKey}}`;
const separator = `{{.Separator}}`;

if (!username || !password) {
alert("Please enter both username and password.");
return;
}

function copyLink(link) {
const fullLink = `${window.location.origin}${link}`;
navigator.clipboard.writeText(fullLink).then(() => {
showToast();
}).catch(err => {
console.error('Failed to copy text: ', err);
});
}

const encryptedCreds = await encryptMessage(`${username}${separator}${password}`);
if (!encryptedCreds) throw new Error('Encryption failed');

const url = `/your-cpe-calendar.ics?creds=${encodeURIComponent(encryptedCreds)}`;
copyLink(url);
} catch (error) {
console.error('Error generating encrypted link:', error);
async function generateEncryptedLink() {
try {
const username = document.getElementById("email").value;
const password = document.getElementById("password").value;

if (!username || !password) {
alert("Please enter both username and password.");
return;
}

const encryptedCreds = await encryptMessage(`${username}${separator}${password}`);
if (!encryptedCreds) throw new Error('Encryption failed');

const url = `/your-cpe-calendar.ics?creds=${encodeURIComponent(encryptedCreds)}`;
copyLink(url);
} catch (error) {
console.error('Error generating encrypted link:', error);
}
}

function showToast() {
const toast = document.getElementById('toast');
toast.className = 'show';
setTimeout(() => {
toast.className = toast.className.replace('show', '');
}, 3000);
}

importPublicKey(pemEncodedKey).then(key => {
encryptionKey = key;
});

</script>
<script src="/static/encryption.js"></script>
</script>
</body>

</html>
</html>
5 changes: 5 additions & 0 deletions static/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b8a0404

Please sign in to comment.