Vous aimez les post-its? Moi oui, du coup je me suis programmé une petite appli web à installer sur mon serveur web perso, pour pouvoir y accéder depuis n’importe ou
Pré-requis :
- serveur web Apache 2.x (pas besoin de php ni de base de données)
- haserl ( apt-get install haserl )
Installation :
- créér un dossier “sticky” contenant un sous-dossier “notes” (ou choisir un autre nom mais penser à le modifier dans le script) dans votre arborescence web
mkdir -p /var/www/sticky/notes
- copier le script principal (voir en bas de ce 1er post) dans /var/www/sticky/, nommer le fichier “notes.cgi” et le rendre exécutable
chown root:root /var/www/sticky/notes.cgi
chmod +x /var/www/sticky/notes.cgi
- autoriser l’écriture dans le sous-dossier “notes” (c’est dans ce dossier que seront stockés les données des post-it)
chown www-data /var/www/sticky/notes
chmod +w /var/www/sticky/notes
- copier le .htaccess suivant dans /var/www/sticky (à modifier selon vos choix)
# Security : only allow localhost by default
# comment or adjust these 3 lines after installation
Order Deny,Allow
Deny from all
Allow from localhost
# Use Apache's basic auth (be sure your server is SSL-enabled!)
# this will also allow multi-user operation
#AuthType Basic
#AuthName "Restricted Access"
#AuthBasicProvider file
#AuthUserFile /etc/apache2/htpasswd.sticky
#Require valid-user
# Security : allow only safe HTTP methods
<LimitExcept POST GET>
Order Allow,Deny
Deny from all
</LimitExcept>
# allow CGIs in current directory
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch -Indexes
AddHandler cgi-script .cgi
(cet .htaccess aura pour effet d’autoriser l’exécution des .cgi dans le répertoire)
- enfin, créer le .htaccess suivant dans /var/www/sticky/notes/ :
Order Allow,Deny
Deny from all
(afin d’interdire l’accès direct aux données des post-it)
Vous devriez avoir l’arborescence suivante :
ls -alR /var/www/sticky
/var/www/sticky:
total 32
drwxr-xr-x 3 root root 4096 oct. 27 19:24 .
drwxr-xr-x 7 root root 4096 oct. 27 18:30 ..
-rw-r--r-- 1 root root 478 oct. 28 12:16 .htaccess
-rw-r--r-- 1 root root 82 oct. 27 18:25 index.html
drwxr-xr-x 2 www-data root 4096 oct. 28 12:28 notes
-rwxr-xr-x 1 root root 10369 oct. 28 12:03 notes.cgi
/var/www/sticky/notes:
total 12
drwxr-xr-x 2 www-data root 4096 oct. 28 12:28 .
drwxr-xr-x 3 root root 4096 oct. 27 19:24 ..
-rw-r--r-- 1 root root 32 oct. 3 21:03 .htaccess
Remarque : pour que les fichiers .htaccess soient bien pris en compte, il faut les autoriser dans votre config Apache principale
nano /etc/apache2/sites-enabled/000-default
remplacer AllowOverride None par AllowOverride All dans :
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
- Vous pouvez accéder à votre appli via l’adresse :
<votre_serveur>/sticky/notes.cgi
Il est possible de crééer un fichier index.html dans /var/www/sticky, pour une redirection automatique
<html><head><meta http-equiv="refresh" content="0; URL=notes.cgi"></head></html>
ainsi vous pourrez accéder directement à l’appli via :
Voici donc le script principal, notes.cgi :
#!/usr/bin/haserl --shell=/bin/bash
<% echo -en "content-type: text/html\r\n\r\n"
#
# Fredo's Sticky Notes
#
# http://agentoss.wordpress.com / fredo696@gmail.com
#
# created 29/09/2013
# last modified 29/10/2013
#
# REQUIRED : bash, haserl. (tested with Apache httpd 2.2 on Debian GNU/Linux)
#
# INSTALL :
# - read the INSTALL file for instructions
# - adjust some variables in the *** PROGRAM'S VARIABLES *** section below
#
# NOTES :
# - sticky notes are displayed in filename order
#
# TODO :
# - short embedded help page (pure CSS modal box)
# - test app on mobile devices
# - allow editing of existing stickies
# - allow some html tags in stickies
# - fix various CSS bugs / fix min-height for .stickynote / Looks ugly on Android's 2.3.6 native webkit browser :(
# - add a hotkey to kill a sticky
# - move sticky notes with mouse?
# - different colors for sticky notes
# - use a nice image/pattern for background
#
# BUGS : please report them to the adress above!
#
# %>
<!DOCTYPE html>
<HTML lang="fr">
<HEAD><META charset="UTF-8">
<!-- disable caching so that pages refresh correctly -->
<!-- <META http-equiv="PRAGMA" content="NO-CACHE">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"> -->
<META name="viewport" content="user-scalable=yes, initial-scale=1, width=device-width">
<%
# Get the user's name from the CGI environment variable
# (in case you are using your web server's auth module)
if [[ -z "$REMOTE_USER" ]];then
username="default"
else
username="$REMOTE_USER"
fi
echo "<TITLE>Sticky Notes : $username</TITLE>"
%>
<STYLE type="text/css">
html {min-height:100%;}
body {color:#564b47; font-size:1em; font-family:Arial, Sans-serif; text-align:center; margin:2%;
/* thanks to http://www.colorzilla.com/gradient-editor/ */
background: #a1dbff;
background: -moz-linear-gradient(top, #a1dbff 0%, #cbebff 53%, #f0f9ff 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a1dbff), color-stop(53%,#cbebff), color-stop(100%,#f0f9ff));
background: -webkit-linear-gradient(top, #a1dbff 0%,#cbebff 53%,#f0f9ff 100%);
background: -o-linear-gradient(top, #a1dbff 0%,#cbebff 53%,#f0f9ff 100%);
background: -ms-linear-gradient(top, #a1dbff 0%,#cbebff 53%,#f0f9ff 100%);
background: linear-gradient(to bottom, #a1dbff 0%,#cbebff 53%,#f0f9ff 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a1dbff', endColorstr='#f0f9ff',GradientType=0 );
}
#footer {position:absolute; bottom:0px; left:0px; text-align:left; font-size:0.60em; opacity:0.5; z-index:-1;}
#footer:hover {opacity:1;}
.stickynote { float:left; border-left:1px solid grey; border-top:1px solid grey; border-right:1px solid black; border-bottom:1px solid black;
box-shadow:4px 4px 6px Grey; padding:10px; margin:10px; text-align:left;
/* adjust stickies dimensions here. TODO: adjust min-height to relative value */
min-width:15%; max-width:35%; min-height:150px;
color:black;
background: gold;
background: -moz-linear-gradient(top, white 0%, gold 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,white), color-stop(100%,gold));
background: -webkit-linear-gradient(top, white 0%,gold 100%);
background: -o-linear-gradient(top, white 0%,gold 100%);
background: -ms-linear-gradient(top, white 0%,gold 100%);
background: linear-gradient(to bottom, white 0%,gold 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='white', endColorstr='gold',GradientType=0 );
/* slower transition for zoom effect */
/* thanks to http://www.solucior.com/fr/15-Zoom_en_CSS3.html */
-webkit-transition: all .2s ease-out;
-moz-transition: all .2s ease-out;
-o-transition: all .2s ease-out;
transition: all .2s ease-out;
z-index:1;
}
.stickynote:hover {
/* zoom effect - slight differences between browsers */
transform: scale(1.25);
-moz-transform: scale(1.25);
-webkit-transform: scale(1.25);
-o-transform: scale(1.25);
z-index:99;
}
.rotated {
/* slight rotation */
transform:rotate(-5deg);
-ms-transform:rotate(-5deg); /* IE 9 */
-webkit-transform:rotate(-5deg); /* Safari and Chrome */
}
pre {font:inherit;
word-wrap:break-word;
white-space:pre-wrap;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
-o-hyphens: auto;
hyphens: auto;
}
a:link {color:LightSlateGrey; text-decoration:none;}
a:active {color:black; text-decoration:none;}
a:visited {color:black; text-decoration:none;}
a:hover {text-decoration:none;color:red;}
.mybutton {max-width:100%; color:black;}
.killnote {position:absolute; top:0px; right:0px;}
.killbutton {border:0px; opacity:0.5; background-color:transparent; color:black; cursor:crosshair;}
textarea {max-width:100%; background-color:transparent; font:inherit; border:hidden;}
</STYLE></HEAD><BODY><DIV>
<%
#
# *** PROGRAM'S VARIABLES ***
#
# uncomment to enable debugging messages
#DEBUG=1
# adjust HERE the ABSOLUTE PATH where to store the stickies
# (this directory must be WRITABLE by the web server)
STICKY_DIR="/var/www/sticky/notes"
# We append the username (so that each user has his own private stickies directory)
#Â (don't change here unless you know what you are doing)
STICKY_DIR="$STICKY_DIR/$username/"
# adjust filename template for mktemp ("man mktemp" for more info)
STICKY_FILENAME="XXXXXX"
# maximum number of characters for the text of a sticky note
STICKY_MAX_LENGTH=400
# MAIN PROGRAM
[[ $DEBUG ]] && echo "(debug) FORM_mode=$FORM_mode | STICKY_DIR=$STICKY_DIR | REMOTE_USER=$REMOTE_USER"
case "$FORM_mode" in
"new")
# new sticky note creation mode
# ensure FORM_textfield is not empty and does not exceed STICKY_MAX_LENGTH chars
len=${#FORM_textfield}
if [[ "$len" -gt 0 && "$len" -le "$STICKY_MAX_LENGTH" ]]; then
# filter FORM_textfield to prevent XSS
FORM_textfield=$( echo "$FORM_textfield" | sed "s/<[^>]*>//g" )
# we use the handy mktemp shell command to create a new file with a unique filename
newfile=$(mktemp --tmpdir="$STICKY_DIR" "$STICKY_FILENAME")
if [[ ! "$newfile" ]]; then
echo "Unable to create new file! Please report the problem to the system admin!"
else
[[ $DEBUG ]] && echo "(debug) FORM_textfield=$FORM_textfield | newfile=$newfile"
# file created ok, write text and make the file readable by all
echo >"$newfile" "$FORM_textfield" && echo "<H1>New sticky note created. Please click <A HREF=$SCRIPT_NAME>here</A> to refresh the page.</H1>"
# TODO: automatically refresh page to show newly created sticky note (javascript)
# we could also add a delay as an anti-flood measure
#sleep 3
fi
else
echo "<H1>Sticky note not created : Text is empty or too long (max. is $STICKY_MAX_LENGTH chars)!</H1>"
fi
;;
"kill")
# kill selected sticky note
# first we sanitize $FORM_id to prevent deleting files outside our private directory
# (remove any non-alphanumeric characters in string, since our filenames are generated by the mktemp command)
filename=${FORM_id//[^a-zA-Z0-9]/}
[[ $DEBUG ]] && echo "(debug) Kill sticky note : $STICKY_DIR/$filename"
[[ $DEBUG ]] || rm "$STICKY_DIR/$filename" && echo "<H1>Your sticky note has been deleted! Go <A HREF=$SCRIPT_NAME>back</A> to the stickies.</H1>"
;;
*)
# default action: display all existing sticky notes for current user
# count=0
if [[ -d "$STICKY_DIR" ]]; then
for f in "$STICKY_DIR"/*; do
#Â check if regular file
if [[ -f "$f" ]];then
# let count++
id=$(basename $f)
# we enclose the plain text between <PRE></PRE> tags so that linefeeds are preserved
echo "<DIV CLASS=\"stickynote rotated\" id=$id><PRE>$(<$f)</PRE>"\
"<DIV CLASS=\"killnote\"><FORM ACTION=\"$SCRIPT_NAME\" METHOD=\"POST\">"\
"<INPUT NAME=\"mode\" TYPE=\"hidden\" VALUE=\"kill\">"\
"<INPUT NAME=\"id\" TYPE=\"hidden\" VALUE=\"$id\">"\
"<BUTTON CLASS=\"killbutton\" TITLE=\"Click to kill this note!\" TYPE=\"submit\">♠</BUTTON>"\
"</FORM></DIV></DIV>"
fi
done
# show message if no stickies found yet
# if [[ $count -eq 0 ]];then
# echo "<H1>There are no stickies yet!</H1>"
# fi
else
# try to create the user's sticky subdir
echo -n "First time user, creating your private stickies directory... "
mkdir "$STICKY_DIR" || echo -e "FAILED... Please check directory permissions!\n"
fi
;;
esac
%><DIV CLASS="stickynote"><FORM ACTION="<% echo -n $SCRIPT_NAME %>" METHOD="POST">
<TEXTAREA NAME="textfield" PLACEHOLDER="Remember the milk!" REQUIRED AUTOFOCUS COLS="30" ROWS="6" MAXLENGTH="<% echo -n $STICKY_MAX_LENGTH %>"></TEXTAREA>
<INPUT NAME="mode" TYPE="hidden" VALUE="new"><BR>
<INPUT TYPE="submit" CLASS="mybutton" VALUE="Create new">
</FORM></DIV></DIV>
<DIV id="footer">Another minimalistic webapp from Fredo (c) 2013 <A HREF="http://agentoss.wordpress.com">Agent OSS</A>.
Just some bits of HTML, CSS, Bash and <A HREF="http://haserl.sourceforge.net/">Haserl</A>. Close your browser to logout.
</DIV></BODY></HTML>
Si vous avez 5 minutes pour tester, n’hésitez pas!
EDIT : màj du script, ajout d’un contrôle de variable dans la partie “kill”)
EDIT2 : légère réorganisation du code, suppression de l’icône embarquée. Utilisation inutile de cat, supprimée.
EDIT3 : modification du .htaccess principal pour une meilleure sécurité