Category: coding

This category contains post about coding, software development, tips&tricks

ionic serve: how to connect over https to use reserved html5 methods such as geolocation

ionic serve: how to connect over https to use reserved html5 methods such as geolocation

 

We all know that at this point https is a must to have.
Many  html5 methods, such as geolocation, are blocked from browsers in order to avoid security issues.
Often, we bump in these “block” even before we deploy our app.
Actually when we deal with these html5 methods, we need to test them during the development phase!
Those using Ionic know it provides an amazing tool that helps during the development :”ionic serve”.
By launching “ionic serve” as shell command, we get a web server (node based) that automatically reloads our app every time we save a change in our code.
This server by default operates over http so, it is not possible to use those html5 methods for example on a smartphone connected to the same local network.

I found the easiest solution: using a proxy with a self signed ssl certificate!

Make a new directory and generate the certificate. ( https://gist.github.com/scrivy/0909468fde8f117a3d66507c8bb3fe12)

Save the following code in proxy.js (https://gist.github.com/justindmyers/266d169e97de20068f78)

Install the required modules and run the proxy

Make sure you’ve launched “ionic serve” it will run on :8100 while the proxy binds :8101

At this point you can type on the browser (The smartphone I mentioned before) https://proxy-ip:8101

PS
There is a thread on the official ionic’s github page, who knows, maybe they will integrate a solution.
Stay tuned! https://github.com/ionic-team/ionic/issues/1686

Intercepting the value change of an @input()

Intercepting the value change of an @input()

I am working on a component that handles pictures upload, for various reasons, the real upload happens externally.
It’s possibile to integrate it in a form or pass to it a callback that is fired after the files are selected.
When I use it within a form, I have another component for showing a progressbar, when I pass to it a callback, I use the embedded progressbar.

The embedded progressbar, needs to know the percentage of the upload, I pass it throught an @input(), when it reaches 100 I want to make the progressbar desappear and get my icon back.

So how to intercept the value?

Well, we have two methods:

1) ngOnChanges

2) set,get

 

input file: how to manipulate an image before uploading

input file: how to manipulate an image before uploading

UPDATE 2017 July 2st
I’ve fixed the source code in order to solve a couple of bug:
1) Files with no exif data crashes the app
2) new Files() on iphone brakes the upload,  formData contains empty files

——

I built an angular2+ component that allows selecting and previewing single images before uploading them through an api.
The component works fine with angular forms.
When the user selects a picture, it often happens that it is not correctly oriented, especially if the picture is taken on the fly from the mobile camera.

The solution is made of three steps:

  1.  Read the exif data and get the orientation
  2.  Accordingly with the orientation, rotate the image by using canvas
  3.  Update the “file” object

In this article I am going to focus on these steps, in a further one, I’d like to  discuss about the whole component (that works with angular form by implementing ControlValueAccessor)

For the steps 1 and 2 I’ve written a little angular provider in order to have a base on which I can add other canvas methods:
(Read the comments in the code below)

After we’ve integrated this provider, we just have to call its methods and update our “file” object
I use  FileReader() in order to show the preview, so I modify the image as soon as I load it.

 

An angular and ionic component for google places autocomplete

An angular and ionic component for google places autocomplete

Many applications need an input for inserting a city or an address.
It is not always a good idea to implement the whole logic in the controller, first of all because we can’t control so well the ngModel and secondly because we could need to use that component in different parts of the application.

I implemented this component on top of some ionic components, but it is very easy to replace the ion-label and ion-input and reuse the same code for a “vanilla” angular project.

What will get in the end of this tutorial, it is a component we can easily integrate in our forms in this way:

types restricts the results that appear in the autocomplete field (see maps api)
returnProperty is the property that we want into the ngModel, in this case just the place_id, by default you”ll get the whole gmaps object

Let’s start with the template:

Nothing special here.
We have the {{label}} passed from the external. #addressInput is needed to find the real <input> tag underneath the ion-input component, of course, the ngModel and a spinner that shows if IsPending is true (while the form is being validate)

Before to see the code of the controller which is the heart of this component, it’s important for you to have an overview of  how forms work in angular and what ControlValueAccessor is.
If you don’t know about it, I strongly advice you to read some good article like this one: https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html

Our component relies on https://angular-maps.com/ (@agm/core) in order to easily interact with google maps, I use it for other stuff in my app, so I’ve decided to use it even here.
In this case it helps to dynamically load the maps api:

Install it before to continue and set up your google api key in your app.module.ts

Finally, the controller (pay attention to the comments):

That’s all.
The thing I’d like to improve is

It is never advisable to directly interact with the dom, we could have problem if we export the app for other platforms not web-based.
I’ll find and post a better solution, probably based on “rederer” .
Do you have any suggestion?

UPDATE

The funcion  validate() is called every time the model changes, so many subscriptions occurres.
The easist, but probably not the best way to avoid it is:


It would be better to find a different way to access to FormControl object, someone pass it to the component through @input()
I’ll give you updates as soon as I find a better way, in the meanwhile any advice is encouraged.

Angular: how to add a progress bar to show during a file upload

Angular: how to add a progress bar to show during a file upload

The vanilla  XMLHttpRequest() method implements the”progress” event  and it is pretty easy to use.
In angularJS (angular 1) we had to wait till the 1.5.something to have this method supported.
In angular (angular 2 which I am talking about) there is no support yet.

The easiest way to get this feature, is to use this good lib:
https://github.com/DarkXaHTeP/angular-progress-http

You can find all the instructions in the github page, the lib is updated and tested with the latest angular version.

Once you’ve got the progress percentage in your controller, you can easily implement a graphical progress bar with few lines of html and css,
An useful guide for ionic2, but it is a good input for any other implementation.
https://www.joshmorony.com/build-a-simple-progress-bar-component-in-ionic-2/

ionic2: how to automatically redirect to the login page

ionic2: how to automatically redirect to the login page

I got a point where it was important to implement an automatic redirection to the login page when the user tries to access a page that should be accessed from logged users only.

I needed something easy to add on every “reserved” page.
The first attempt was to create a service, I immediately faced with a problem:
The NavController (needed for the page change) can’t work form inside a service.

This is the error I got:
No provider for NavController

https://github.com/driftyco/ionic/issues/9581

I decided for a component.
The working principle is easy:

  1. When the app starts deletes the storage obj “user”
  2. Immediately after it tries to get a new obj from an api call by using the access token stored in the storage obj “session”
  3. If the call succeeds it saves the new storage obj “user”
  4. Every page that needs to be “protected” includes the component <login-redirect>
  5. <login-redirect> checks if the storage obj “user” exists, if it does not, it redirects to the login page passing a parameter used from the login component to redirect to a page(or back) if the login succeeds
  6. When the login succeeds, the login component calls the api again to fetch and set the storage obj “user”
  7. The login page redirects to the right page (passed as parameter on the point 5)

Let’s see some code:

I don’t need to modify the template or the scss file.

controller

The @Input() is used to read from the tag’s attribute “redirect” the page to pass to the login component (we’ll see it later)

The login component has some logic like this

In every page I want to reserve for logged users, I add this line in the template


This method works fine, anyway I don’t know yet if this is the best method to achieve the result, for example a little side effect is that the page we want to protect appears for a short time before the redirection.
As soon as I discover a better method I’ll share it.

Any suggestion?

ionic storage and objects: how to add a property

ionic storage and objects: how to add a property

Ionic has a really useful module to locally store the data that the app wants to save.
I use it for many things, for example to save the auth token the user receives after the login.
It is a very simple layer that automatically chooses the best available store engine in the browser.
If you want to go deeper http://ionicframework.com/docs/storage/

The usage is super easy :

The problem is when you come to deal with objects.
The api is not capable to add or remove a property, you have to replace the whole object.

For me this is extremely annoying, plus if you do it often you get your code quite “dirty”.
I decided to write a little provider that by saving a json string, allows me to add a single property to the object.

$ ionic g provider MtfStorage

To use it, you just have to import the provider in the component you like


 

How to define the right scope context (this) while passing a callback function to a component

How to define the right scope context (this) while passing a callback function to a component


A super common situation is to pass a callback function to component.

Template

 

Controller

 

The component takes the callback in input

In this scenario the method this.apicall(value) would fail since “this” is not what we expect.
To be sure that “this” refers to the controller’s scope, we can add a simple line on its constructor:

 

Solution


 

Add a layer over an element with 1 css rule

Add a layer over an element with 1 css rule


Sometime we want to make an element like a  picture darker to better read the text over it,
we can solve it with 1 css rule without adding any html element.

Parameters are pretty clear, anyway the last one is the opacity.

vsftpd con utenti mysql e custom chrooted homedir

vsftpd con utenti mysql e custom chrooted homedir

I motivi per i quali possiamo voler scegliere vsftpd come server ftp, sono innumerevoli e non saranno oggetto di questo articolo.
Mi limito a dire che personalmente, l’ho scelto per la sua sicurezza, snellezza, prestazioni.
Del resto, si tratta di una soluzione scelta da redhat e consigliata da ibm.
Come al solito, tutto parte dalle mie esigenze per cui descriverò la mia soluzione e non tutte le possibilità che questo magnifico strumento offre.

La prima caratteristica desiderata è una gestione degli users tramite mysql e questo tramite pam è abbastanza semplice.
Leggermente più complicato è stato far si che più utenti potessero condividere la stessa homedir (immaginate 3 sviluppatori diversi che lavorano sullo stesso sito e di cui si vogliono tracciare gli accessi con differenti login)
Tutti gli accessi saranno chroot ossia gli utenti non potranno navigare l’intero filesystem.

La difficoltà principale è che non si può scrivere la homedir chroot in uno dei campi del db e sperare che vsftpd legga quel valore.
Questo limita di fatto, la possibilità di avere una gestione centralizzata degli accessi (in maniera nativa), per esempio tramite un front-end web, ecco come ho deciso di procedere e soprattutto di aggirare tale limitazione:

Settings

Sulla debian wheezy usata, avendo già installato e configurato mysql, è bastato un:

Le libpam-mysql sono fondamentali per permettere a vsftpd di leggere gli utenti presenti su mysql.

Aggiungere l’utente di sistema vsftpd:

Loggarsi come amministratore su mysql e creare database, utente e tabella.

Dentro /etc/pam.d/vsftpd commentare tutto e lasciare le seguenti righe che specificano a vsftpd come e dove cercare gli utenti su database

chiaramente è possibile cambiare i valori di crypt, debug e verbose a piacimento, tuttavia inizialmente è preferibile avere dei log prolissi.

L’ultimo file di configurazione è quello fondamentale per vsftpd ovvero /etc/vsftpd.conf
Per il significato di ognuna delle seguenti direttive vi rimando alla guida ufficiale.

Una delle direttive specificate in vsftpd.conf è la “user_config_dir”
che abbiamo settato a /etc/vsftpd/user_conf
Questa dice vsftpd dove cercare i settaggi specifici per ogni utente ed è il modo più semplice per avere una home diversa per ognuno di loro ma anche per poter avere più users con la stessa home.

Prima di tutto assicuriamoci di creare la directory che conterrà le configurazioni specifiche:

Il formato è molto semplice, basta creare un file con il nome utente presente nel db e mettere dentro poche righe di testo:

Non dimenticatevi di riavviare il servizio

Adesso tutto è funzionante ma è certamente scomodo dover inserire a mano gli utenti nel db e poi creare il relativo file di configurazione dentro /etc/vsftpd/user_conf
Per rendere tutto molto semplice ho creato un piccolo script perl che fa tutto il lavoro sporco per noi.
Lo script essenzialmente permette di aggiungere ed eliminare utenti in maniera velocissima, si preoccuperà lui di inserire o eliminare la voce del db e di conseguenza il file di configurazione necessario.
Lo script crea automaticamente la homeDir specificata e imposta i permessi corretti per poter lavorare in chroot.
Per un corretto chroot infatti è necessario che la directory specificata, non abbia i permessi di scrittura e che contenga all’interno una seconda directory con tali permessi, questa seconda directory sarà l’unico punto in cui l’utente potrà effettivamente scrivere.
Se non si rispettà questo schema, vsftpd non funzionerà correttamente e sui nostri client ftp leggeremo un laconico:

500 OOPS: vsftpd: refusing to run with writable root inside chroot ()

Entrambe le directory, devono poi appartenere a vsftpd e gruppo nogroup.
Lo script permette anche di vedere la lista di utenti presenti, modificare la password o la homeDir e di copiare automaticamente un file dentro la directory con i permessi di scrittura.
Quest’ultima caratteristica risulta utile nel caso si voglia lasciare all’utente un readme oppure nel caso si tratti di un sito web, creare una index di default.

Per aggiungere un utente basta digitare:

Tutte le modifiche saranno attive in tempo reale senza la necessità di riavviare il server.
L’unico “sforzo” richiesto è editare lo script per aggiungere i propri parametri di configurazione
del db, la directory dove vengono scritte le configurazioni degli utenti, uid e gid di vsftpd.
Insomma operazione da pochi minuti.

Lo script lo trovi su github:
https://github.com/bogomips/syncFtp.pl

Buon divertimento con vsftpd !

PS
Questa guida è stata utilizzata come base per un’altra guida su debianizzati.org dove è anche stata integrata una sezione relativa a TLS:
http://guide.debianizzati.org/index.php/Installare_un_server_vsFTPd_con_utenti_virtuali_su_MySQL