Mise à jour d’un serveur Kimsufi (OVH) depuis Debian 8 (Jessie) vers Debian 9 (Stretch)

Il faut régulièrement penser à mettre à jour son serveur Kimsufi.

Je vais essayer d’expliquer brièvement les étapes à suivre pour cela.

  1. On va d’abord sauvegarder les données :
    mkdir /root/svg_special; cp -R /var/lib/dpkg /root/svg_special/; cp /var/lib/apt/extended_states /root/svg_special/; dpkg --get-selections "*" > /root/svg_special/dpkg_get_selection; cp -R /etc /root/svg_special/etc
  2. Ensuite il est conseillé d’utiliser screen pour pouvoir se reconnecter (avec screen -r) à en cas de déconnexion :
    screen
  3. On va effectuer une mise à jour des paquets avec apt-get update && apt-get upgrade
  4. Le processus de mise à niveau décrit sur le site de Debian a été conçu pour des mises à niveau des systèmes Jessie « purs » sans paquet provenant d’autres sources. Pour une meilleure fiabilité du processus de mise à niveau, vous pouvez supprimer ces paquets du système avant de commencer la mise à niveau. :
    aptitude search '~i(!~ODebian)'
  5. On peut lancer la commande dpkg --audit pour s’assurer que tout est bon avant la migration. On peut également taper dpkg --get-selections "*" | more et vérifier qu’aucun paquet n’est en on hold
  6. Maintenant il faut remplacer tous les “jessie” de /etc/apt/sources.list par des “stretch”, ce qui va donner chez moi :
    deb http://ftp.fr.debian.org/debian stretch main non-free
    
    deb http://debian.mirrors.ovh.net/debian/ stretch main
    deb-src http://debian.mirrors.ovh.net/debian/ stretch main
    
    deb http://security.debian.org/ stretch/updates main
    deb-src http://security.debian.org/ stretch/updates main
    

    On vérifiera aussi les autres fichiers qui peuvent se trouver dans /etc/apt/sources.list.d

  7. Si vous utilisez MySQL, sachez qu’avec Stretch vous pourriez passer sur MariaDB… Si vous souhaitez utiliser MySQL, on peut se référer à ce blog post
    • On ajoute/édite le fichier source pour mysql : nano /etc/apt/sources.list.d/mysql.list
    • On y ajoute les sources suivantes (pour mysql-5.7) :
      deb http://repo.mysql.com/apt/debian/ stretch mysql-5.7
      deb-src http://repo.mysql.com/apt/debian/ stretch mysql-5.7
      
    • On ajoute la clé publique de ce repo :
      wget -O /tmp/RPM-GPG-KEY-mysql https://repo.mysql.com/RPM-GPG-KEY-mysql
      apt-key add /tmp/RPM-GPG-KEY-mysql
      rm /tmp/RPM-GPG-KEY-mysql
      
  8. Il est recommandé d’utiliser le programme /usr/bin/script pour enregistrer une transcription de la session de mise à niveau. Ainsi, quand un problème survient, on a un enregistrement de ce qui s’est passé. Pour démarrer un enregistrement, taper :
    script -t 2>~/upgrade-stretch.time -a ~/upgrade-stretch.script
  9. On passe aux choses sérieuses, en commençant par mettre à jour les listes des paquets :
    apt-get update
  10. On va vérifier qu’on a la place suffisante (un message explicite apparait sinon) :
    apt-get -o APT::Get::Trivial-Only=true dist-upgrade
  11. On va maintenant faire une mise à jour minimale :
    apt-get upgrade
  12. Et à partir de là le système va vous questionner… en général choisir l’option par défaut si vous ne savez pas quoi répondre
  13. Puis on continue avec
    apt-get dist-upgrade

Cette dernière étape va durer un certain temps. Une fois terminé, vous pouvez redémarrer le serveur pour s’assurer que tout va bien.

Avec phpmyadmin vous pourriez recevoir l’erreur suivante :

PHP Warning: require_once(): open_basedir restriction in effect. File(/usr/share/php/php-php-gettext/gettext.inc) is not within the allowed path(s): (/usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/share/php/php-gettext/) in /usr/share/phpmyadmin/libraries/common.inc.php on line 77
PHP Warning: require_once(/usr/share/php/php-php-gettext/gettext.inc): failed to open stream: Operation not permitted in /usr/share/phpmyadmin/libraries/common.inc.php on line 77

Dans ce cas là, il faut rajouter /usr/share/php/php-php-gettext/ dans le fichier /etc/phpmyadmin/apache.conf sur la ligne open_base_dir. Ce qui va donner la ligne : php_admin_value open_basedir /usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/share/php/php-gettext/:/usr/share/php/php-php-gettext/

J’ai eu quelques soucis avec fail2ban qui ne démarrait pas. J’ai pu résoudre en consultant le Troubleshooting de leur wiki. Il s’agissait du fichier /etc/fail2ban/jail.d/defaults-debian.conf qui avait été créé avec une entrée invalide. Il a suffit de le supprimer.

Une fois les erreurs corrigées, on va nettoyer tous les paquets avec

apt-get autoremove

Invisible character with IE when using Intl.DateTimeFormat

As explained in some threads, Internet Explorer adds some invisible extra characters when returning a date from the JavaScript function new Intl.DateTimeformat.

var day = "Thursday";
var intlDay = new Intl.DateTimeFormat('en-US', {weekday:"long"}).format(new Date(2019,1,7));
console.log(day === intlDay); // return FALSE with IE
intlDay = intlDay.replace(/\u200E/g, ''); // replace \u200E
console.log(day === intlDay); // return TRUE with IE

The trick is to replace \u200E in the returned string.

Envoie d’email et spam (via OVH)

Si on envoie des emails depuis notre propre serveur, avec notre propre domaine, certaines mailbox (comme Gmail) pourraient vous détecter comme du spam !

Pour éviter cela, il faut prendre quelques précautions.

Type “SPF”

Tout d’abord, il faut ajouter une entrée SPF via le gestionnaire de domaine d’OVH. Le wizard va aider à composer la chaine qui sera enregistrée pour le domaine.

Il faudra fournir :

  • L’IPv4 du serveur qui envoie les emails
  • L’IPv6 du serveur qui envoie les emails
  • Inclure le MX d’OVH (include:mx.ovh.com)

Au final, le champ SPF devrait ressembler à ça :
300 IN TXT "v=spf1 a mx ip4:1.2.3.4 ip6:2001:41d0:a:abcd::1/128 include:mx.ovh.com -all"

Type “DKIM”

Cette fois on va ajouter une entrée de type “DKIM”.

Il faudra utiliser https://dkimcore.org/tools/ et :

  • Le sous domaine est fourni par l’outil (exemple : 1547992053.kodono._domainkey)
  • Choisir la version “DKIM 1”
  • Type de clé : RSA
  • La clé publique générée par l’outil dkimcore

Au final, le champ DKIM devrait ressembler à ça :
1547992053.kodono._domainkey.kodono.info. 0 DKIM v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQE...anzmm2RIpt0tV3gwTGwuLQIDAQAB;t=s;

On pourra ensuite utiliser https://github.com/louisameline/php-mail-signature qui est une librairie PHP et qui aide à signer les emails qu’on envoie en PHP.

Type “DMARC”

Enfin, on ajoute une entrée de type “DMARC”.

Il faudra utiliser :

  1. Le sous-domaine doit être _dmarc
  2. Règle pour le domaine : none

Au final, le champ DMARC devrait ressemble à ça :
_dmarc.kodono.info. 0 DMARC v=DMARC1; p=none;

Ajout d’un reverse

Il va falloir ajouter un reverse (PTR) pour l’IPv4 et l’IPv6 du serveur. Cela se fait via la console de votre serveur (par exemple via le site Kimsufi si votre serveur est là bas).

Tester

Une fois vos emails créés, vous pouvez les tester grâce aux sites https://www.mail-tester.com/ et https://dkimvalidator.com/

Create a self-signed certificate for localhost testing with IE11 and Webpack

Sources:

If you develop with Webpack under Windows and you want to open your localhost server in HTTPS with IE11 you may receive a message like :

“Content was blocked because it was not signed by a valid security certificate.”

Below I explain the steps to make it work with IE11:

  1. Open Powershell in Administrator mode
  2. Type (no need to change anything, just copy/paste):
    New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname localhost -FriendlyName "Dev localhost" -NotAfter (Get-Date).AddMonths(240) -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")

    It should return a Thumbprint:

       PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\my
    
    Thumbprint                                Subject
    ----------                                -------
    1D97DFF290FBACE0871F16AD1B38172F253CA048  CN=localhost

    You may want to open certlm.msc to see the new certificate in Personal

  3. Export to .cer with the below Powershell command (make sure to replace 1D97DFF290FBACE0871F16AD1B38172F253CA048 with the Thumbprint you received before)… it will be exported to C:\localhost.cert (but you can change the path):
    Export-Certificate -Cert Cert:\LocalMachine\MyD97DFF290FBACE0871F16AD1B38172F253CA048 -FilePath C:\localhost.cer (example: Export-Certificate -Cert Cert:\LocalMachine\My\PREVIOUS_Thumbprint_HERE -FilePath C:\localhost.cer)
  4. We now need to export to .pfx with the below Powershell commands:
    $CertPassword = ConvertTo-SecureString -String "YourPassword" -Force –AsPlainText
    Export-PfxCertificate -Cert cert:\LocalMachine\My79C7928D055B21AAA0Cfe2F6BE1A5C2CA83B30 -FilePath C:\localhost.pfx -Password $CertPassword
    
  5. Next we’ll use the opensource application called XCA: download and install it.
  6. Open XCA and go to : File > New Database
  7. Choose where you want to have this database and provide a password (to make it easy, you can choose the same “YourPassword” than before)
  8. Go to tab Certificates
  9. Click Import and select the previous created localhost.cer
  10. Once imported, right click the cert and Export > File, then select “*.crt” for the file format
  11. Go to the Private Keys tab and click on Import PFX
  12. Select the previously created PFX and click Import All
  13. Right click on “localhost_key” and Export > File, then select “PEM Private (*.pem)” for the file format
  14. Close XCA and go to the folder with all your files
  15. Double-click on the file localhost.crt you have just created
  16. Windows shows a popup with a "Install Certificate..." button; Click on this button
  17. Choose Current User, and next, click on “Place all certificates in the following store”, and browse to “Trusted Root Certification Authorities”
  18. Finally, in your Webpack config, you should enter something like the below:
    module.exports = {
      //...
      devServer: {
        https: {
          key: fs.readFileSync('C:\\localhost.pem'),
          cert: fs.readFileSync('C:\\localhost.crt')
        }
      }
    };
    

Launch your webpack server and open IE to your localhost server. It should work…

If you need to do CORS request, you may need to open IE settings, then go to Security and make sure to add localhost in the Local Intranet/Trusted Sites, then click on “Custom Level…”, go to “Miscellaneous” and select “Enable” for “Access data sources across domains”.

Sharepoint DateRangesOverlap value

(this is a copy of a post that is not available anymore)

DateRangesOverlap Value Type

I don’t know if any back-end developers have run into this same issue when working with the SPQuery to pull expanded recurrence date, but from here, not all DateRangesOverlap Value types work the way they should. And they’re cryptically-documented, where mentioned at all. The basics are that you can return dates that “overlap” a given scenario. The overlapping varies depending on scenario, as follows:

<Year />
This is supposed to get all events within:
(a) Today’s year (if no CalendarDate is passed), or
(b) the date passed in QueryOptions as CalendarDate.

Actually, it returns all dates from [Today] into the future. It ignores:
(a) the CalendarDate, and
(b) the end of the current year

<Month />
Performs consistently as expected, with the exception that its definition of “month” is more of a “month view.” A month view consists of all of the weeks which contain days in that month. In other words, the month view for May 2012 begins on April 29, 2012, because May 1 is on a Tuesday and the “month view” consists of full weeks. Likewise, the May 2012 month view ends on June 5, 2012. This means that pulling all of the dates for May 2012 will return all events for April 29 – June 5.

However, even though April 29 is the beginning of the May month view, when passed as the CalendarDate, it will return the April month view. See below for how this affects date calculations based on pulling data for a given month.

<Week />
Performs exactly like <Month />, but only returns the corresponding week for:
(a) Today, or
(b) CalendarDate

<Today />
Returns just the events for Today.

<Now />
Contrary to most documentation, <Now /> doesn’t “work” but rather defaults to the same results as <Year />.

In fact, <Year /> is the default. If you leave off the entire WHERE clause, but include the RecurrenceDate and fRecurrence fields and the QueryOptions (CalendarDate will be ignored), you get the same results as <Year />.

CalendarDate

In QueryOptions, if the CalendarDate is set, it needs the date to be a string in the format:
yyyy-mm-ddThh:mm:ssZ

In most cases, setting the CalendarDatewhen needed to the real date on which you want to base your range will work just fine, as long as you set the time in the Z-notation to noon. The reason for the noontime setting is to make allowance for all-day events within the given range. These tend to get messed up when viewing is based on a midnight or early morning time. Basing the range on noon alleviates the issue. (At least it does for US time zones; I confess that I haven’t tested them all.)

Interclassement MySQL pour le français

Quel interclassement (dit aussi collation) choisir pour sa base MySQL afin d’y enregistrer des caractères français (entre autres) ?

L’interclassement a deux fonctions :

  1. Permettre l’ordonnancement correct d’une liste de caractères (pour indiquer que le “é” vient après le “e”, ou que les majuscules viennent avant les minuscules, etc)
  2. Permettre de savoir quand un caractère est “équivalent” à un autre (dans les requêtes WHERE que, par exemple, le caractère “e” est équivalent à “E”, “é”, “è” ou “ê”)

Sur fluxbb on retrouve une très bonne explication. Je copie qu’une partie, mais allez lire cet article vraiment complet :

MySQL permet de choisir comment les données seront classées (ORDER BY) par ce qui est appelé une « collation » (COLLATE). Ceci permet de répondre, par exemple, au problème classique de la sensibilité à la casse :

  • Les majuscules doivent-elles précéder les minuscules, ou bien faut-il considérer A et a comme de même valeur ?
  • La sensibilité aux accents : comptent-ils dans le tri ? Font-ils une différence lors de la recherche ?
  • La possibilité qu’un caractère (ligature oe) puisse correspondre à plusieurs (o suivi de e) : c’est ce qu’Unicode appelle « l’expansion ».

Toutes les collations ont un nom qui commence par le jeu de caractère auquel elles sont liées, et se terminent par l’une de ces trois abréviations :

  • _bin comme binary : les caractères sont dans l’ordre de leurs numéros de code (ce qui donne d’abord toutes les majuscules, puis toutes les minuscules, puis les lettres accentuées, en vrac).
  • _cs comme case sensitive : les caractères sont triés selon le ou les langages de référence, mais de manière sensible à la casse.
  • _ci comme case insensitive : idem, mais en ignorant la casse.

Il est possible de définir plusieurs niveaux : de la colonne jusqu’à toute la base de données. Ainsi on peut définir une collation pour une colonne qui sera différente de celle de la table.

Au final, on peut utiliser utf8_unicode_ci : utf8 indique qu’on peut enregistrer une large palette de caractères (on utilisera utf8mb4 si on souhaite enregistrer des émoticones en plus), unicode_ci va permettre un bon tri tout en ignorant la casse.

Content Security Policy (CSP) blocks scripts from Violentmonkey / Greasemonkey

I wanted to inject some codes on Github, however I received Content Security Policy errors. It’s because Github blocks this kind of injected code.

To bypass this restriction I installed the addon Content Security Policy Override (if you have Firefox you can install this Chrome addon using Chrome Store Foxified) then I applied the below rule in the addon’s settings :

[
  ["https://github\\.com/*", [
    ["script-src", "script-src 'self' 'unsafe-inline' 'unsafe-eval'"]
  ]]
]

Now my Violentmonkey script works.

Remove custom properties/metadata for an Office document [javascript]

I have this document library on Sharepoint where I have one custom column called Metadata and that is a lookup to another list on my Sharepoint.

When the users download an Office document from this library and then re-upload it we could have the below error message:

There is at least one lookup column that enforces a relationship behavior and contains values that reference one or more non-existent items in the target list.

It’s because the Office documents keep the custom columns from the document library from where they have been downloaded… In that case the file tries to reassign the Metadata with an ID that doesn’t exist anymore… causing this issue!

Because I’m using a homemade interface to upload documents, I’ve been able to pass some code to delete the file’s properties on-the-fly before pushing it into the document library.

To do so, you need JSZip that will permit to unzip the Office document in order to retrieve the file docProps/custom.xml and to change the properties we want before the final upload.

Let’s imagine my page contains an <input type="file">, and that I have already loaded JSZip. Then I use FileReader:

var fileReader = new FileReader();
fileReader.onloadend = function(e) {
  // content is the "arraybuffer" that represents my file
  var content = e.target.result;
  // check the file's extension (here "docx", "xlsx", and "pptx", but we could add more extensions
  var ext=file.name.split(".").slice(-1)[0];
  switch (ext) {
    case "docx":
    case "xlsx":
    case "pptx": {
      // load content in JSZip
      JSZip.loadAsync(content)
      .then(function(zip) {
        // unzip the file that contains metadata/properties
        return zip.file("docProps/custom.xml").async("text")
        .then(function(txt) {
          // replace the faulty column
          txt = txt.replace(/name="Metadata"><vt:lpwstr>\d+<\/vt:lpwstr>/,'name="Metadata"><vt:lpwstr><\/vt:lpwstr>');
          // reinject the new file
          zip.file("docProps/custom.xml", txt);
          return zip.generateAsync({type:"arraybuffer"})
        })
      })
      .then(function(content) {
        // do something with your content
        // for example (https://aymkdn.github.io/SharepointPlus/): $SP().list("my_list").createFile({content:content, filename:file.name})
      })
      break;
    }
    default: {
      // for the other files, treat them normally
      // for example (https://aymkdn.github.io/SharepointPlus/): $SP().list("my_list").createFile({content:content, filename:file.name})
    }
  }
}
fileReader.onerror = function(e) {
  console.error(e.target.error);
}
fileReader.readAsArrayBuffer(file);

Émuler Raspberry Pi sous Windows

Depuis que j’ai fait assistant-plugins, j’ai plusieurs utilisateurs qui m’ont demandé comment l’installer sur leur Raspberry. Ce système est censé être similaire à une Debian, cependant ils semblent y avoir des différences… J’ai donc cherché à émuler cet OS sous mon Windows 10.

Sources :

Voici les étapes :

  1. Télécharger la dernière version disponible de QEMU sur le site https://qemu.weilnetz.de/w32/ (par exemple qemu-w32-setup-20171211.exe au moment où j’écris cet article)
  2. Une fois téléchargé, on va faire un clique-droit et dézipper qemu-w32-setup-20171211.exe vers qemu-w32-setup-20171211
  3. Télécharger la dernière version de Raspbian via https://www.raspberrypi.org/downloads/raspbian/ dans le répertoire qemu-w32-setup-20171211/ (ou via ce lien https://downloads.raspberrypi.org/raspbian_latest) (par exemple je prends la version lite qui se nomme 2017-11-29-raspbian-stretch-lite.zip)
  4. Télécharger le kernel dans le répertoire qemu-w32-setup-20171211/ via https://github.com/dhruvvyas90/qemu-rpi-kernel (par exemple j’ai pris kernel-qemu-4.4.34-jessie)
  5. On va immédiatement agrandir la taille de notre image de 5G (pour éviter d’avoir des problèmes d’espace disque plus tard). Pour cela on va se rendre dans le dossier qemu-w32-setup-20171211/ avec CMD et on va taper : qemu-img.exe resize 2017-11-29-raspbian-stretch-lite +5G
  6. On peut lancer l’émulation avec la commande (voir tous les paramètres disponibles) : qemu-system-arm.exe -kernel -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -drive "file=,index=0,media=disk,format=raw" -redir tcp:2222::22
    (ce qui va donner chez moi : qemu-system-arm.exe -kernel kernel-qemu-4.4.34-jessie -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -drive "file=2017-11-29-raspbian-stretch-lite.img,index=0,media=disk,format=raw" -redir tcp:2222::22)
  7. Si tout se passe comme prévu l’image devrait démarrer et arriver jusqu’à vous demander un login (pi) et pass (raspberry) … Attention, par défaut c’est un clavier QWERTY qui est appliqué, il faut donc taper rqspberry pour le password.
  8. On va passer le clavier en français en tapant : sudo apt-get install console-data, puis sudo sudo dpkg-reconfigure console-data
    On choisit select keymap from fullist puis pc / azerty / French / Same as X11 (latin 9) / Standard.
  9. Si le clavier continue à être en anglais, taper : sudo dpkg-reconfigure keyboard-configuration en sélectionnant le clavier par défaut proposé, puis pour la langue, choisir Other puis French, et ensuite les propositions par défaut.
    Et finalement la commande : sudo setupcon
  10. On va maintenant finir d’agrandir notre partition. Pour cela on tape : sudo fdisk /dev/sda et on suit les instructions ci-dessous :
    • On affiche la table des partitions avec la lettre “p”. On va noter le chiffre qui apparait dans la colonne Start pour la deuxième ligne (celle qui correspond à la partition de type Linux) (chez moi cela vaut 94208)
    • On efface la partition principale avec la lettre “d” (cela devrait être la 2)
    • On crée une nouvelle partition avec la lettre “n”, puis on choisit primary avec “p” et la position “2”
    • Pour le premier secteur on va utiliser la valeur trouvée précédemment (94208 pour moi)
    • On appuie sur “Enter” pour le last sector (pour utiliser la valeur proposée)
    • À la question Do you want to remove the signature?, répondre “N”
    • On écrit la table de partition avec “w”
    • Puis on reboot avec sudo shutdown -r now
    • Après le reboot on va terminer par : sudo resize2fs /dev/sda2
  11. Maintenant on va augmenter la taille du swap : sudo nano /etc/dphys-swapfile où on va remplacer CONF_SWAPSIZE=100 par CONF_SWAPSIZE=1024
  12. On redémarre le service avec : sudo /etc/init.d/dphys-swapfile stop puis sudo /etc/init.d/dphys-swapfile start

Maintenant l’émulateur est prêt à être utilisé. Se reporter aux deux sources fournies en début d’article pour plus de détails et des options supplémentaires !