Saturday, June 30, 2018
Creating Pretty Popup Messages Using SweetAlert2
Every now and then, you will have to show an alert box to your users to let them know about an error or notification. The problem with the default alert boxes provided by browsers is that they are not very attractive. When you are creating a website with great color combinations and fancy animation to improve the browsing experience of your users, the unstyled alert boxes will seem out of place.
In this tutorial, you will learn about a library called SweetAlert2 that allows us to create all kinds of alert messages which can be customized to match the look and feel of our own website.
Display Simple Alert Messages
Before you can show all those sweet alert messages to your users, you will have to install the library and include it in your project. If you are using npm or bower, you can install it by running the following commands:
npm install sweetalert2 bower install sweetalert2
You can also get a CDN link for the latest version of the library and include it in your webpage using script tags:
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@7.12.15/dist/sweetalert2.all.min.js"></script>
Besides the JavaScript file, you will also have to load a CSS file which is used to style all the alert boxes created by the library:
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/sweetalert2@7.12.15/dist/sweetalert2.min.css'>
Once you have installed the library, creating a sweet alert is actually very easy. All you have to do is call the swal()
function. Just make sure that the function is called after the DOM has loaded.
There are two ways to create a sweet alert using the swal()
function. You can either pass the title, body text and icon value in three different arguments or you can pass a single argument as an object with different values as its key-value pairs. Passing everything in an object is useful when you want to specify values for multiple arguments.
When a single argument is passed and it is a string, the sweet alert will only show a title and an OK button. Users will be able to click anywhere outside the alert or on the OK button in order to dismiss it.
When two arguments are passed, the first one becomes the title and the second one becomes the text inside the alert. You can also show an icon in the alert box by passing a third argument. This can have any of the five predefined values: warning
, error
, success
, info
, and question
. If you don't pass the third argument, no icon will be shown inside the alert message.
document.querySelector(".first").addEventListener('click', function(){ swal("Our First Alert"); }); document.querySelector(".second").addEventListener('click', function(){ swal("Our First Alert", "With some body text!"); }); document.querySelector(".third").addEventListener('click', function(){ swal("Our First Alert", "With some body text and success icon!", "success"); });
Configuration Options to Customize Alerts
If you simply want to show some basic information inside an alert box, the previous example will do just fine. However, the library can actually do a lot more than just simply show users some text inside an alert message. You can change every aspect of these alert messages to suit your own needs.
We have already covered the title, the text, and the icons inside a sweet alert message. There is also an option to change the buttons inside it and control their behavior. By default, an alert will only have a single confirm button with text that says "OK". You can change the text inside the confirm button by setting the value of the confirmButtonText
property. If you also want to show a cancel button in your alert messages, all you have to do is set the value of showCancelButton
to true
. The text inside the cancel button can be changed using the cancelButtonText
property.
Each of these buttons can be given a different background color using the confirmButtonColor
and cancelButtonColor
properties. The default color for the confirm button is #3085d6
, while the default color for the cancel button is #aaa
. If you want to apply any other customization on the confirm or cancel buttons, you can simply use the confirmButtonClass
and cancelButtonClass
properties to add a new class to them. Once the classes have been added, you will be able to use CSS to change the appearance of those buttons. You can also add a class on the main modal itself by using the customClass
property.
If you interacted with the alert messages in the first example, you might have noticed that the modals can be closed by pressing either the Enter or Escape key. Similarly, you can also click anywhere outside the modal in order to dismiss it. This happens because the value of allowEnterKey
, allowEscapeKey
, and allowOutsideClick
is set to true
by default.
When you show two different buttons inside a modal, the confirm button is the one which is in focus by default. You can remove the focus from the confirm button by setting the value of focusConfirm
to false
. Similarly, you can also set the focus on the cancel button by setting the value of focusCancel
to true
.
The confirm button is always shown on the left side by default. You have the option to reverse the positions of the confirm and cancel buttons by setting the value of reverseButtons
to true
.
Besides changing the position and color of buttons inside the alert messages, you can also change the background and position of the alert message or the backdrop around it. Not only that, but the library also allows you to show your own custom icons or images in the alert messages. This can be helpful in a lot of situations.
You can customize the backdrop of a sweet alert using the backdrop
property. This property accepts either a Boolean or a string as its value. By default, the backdrop of an alert message consists of mostly transparent gray color. You can hide it completely by setting the value of backdrop
to false
. Similarly, you can also show your own images in the background by setting the backdrop
value as a string. In such cases, the whole value of the backdrop
string is assigned to the CSS background
property. The background of a sweet alert message can be controlled using the background
property. All alert messages have a completely white background by default.
All the alert messages pop up at the center of the window by default. However, you can make them pop up from a different location using the position
property. This property can have nine different values with self-explanatory names: top
, top-start
, top-end
, center
, center-start
, center-end
, bottom
, bottom-start
, and bottom-end
.
You can disable the animation when a modal pops up by setting the value of the animation
property to false
. The library also provides a timer
property which can be used to auto-close the timer once a specific number of milliseconds have passed.
In the following example, I have used different combinations of all the properties discussed in this section to create four different alert messages. This should demonstrate how you can completely change the appearance and behavior of a modal created by the SweetAlert2 library.
document.querySelector(".first").addEventListener("click", function() { swal({ title: "Show Two Buttons Inside the Alert", showCancelButton: true, confirmButtonText: "Confirm", confirmButtonColor: "#00ff99", cancelButtonColor: "#ff0099" }); }); document.querySelector(".second").addEventListener("click", function() { swal({ title: "Are you sure about deleting this file?", type: "info", showCancelButton: true, confirmButtonText: "Delete It", confirmButtonColor: "#ff0055", cancelButtonColor: "#999999", reverseButtons: true, focusConfirm: false, focusCancel: true }); }); document.querySelector(".third").addEventListener("click", function() { swal({ title: "Profile Picture", text: "Do you want to make the above image your profile picture?", imageUrl: "https://images3.imgbox.com/4f/e6/wOhuryw6_o.jpg", imageWidth: 550, imageHeight: 225, imageAlt: "Eagle Image", showCancelButton: true, confirmButtonText: "Yes", cancelButtonText: "No", confirmButtonColor: "#00ff55", cancelButtonColor: "#999999", reverseButtons: true, }); }); document.querySelector(".fourth").addEventListener("click", function() { swal({ title: "Alert Set on Timer", text: "This alert will disappear after 3 seconds.", position: "bottom", backdrop: "linear-gradient(yellow, orange)", background: "white", allowOutsideClick: false, allowEscapeKey: false, allowEnterKey: false, showConfirmButton: false, showCancelButton: false, timer: 3000 }); });
Important SweetAlert2 Methods
Initializing different sweet alert messages to show them to users is one thing, but sometimes you will also need access to methods which control the behavior of those alert messages after initialization. Fortunately, the SweetAlert2 library provides many methods that can be used to show or hide a modal as well as get its title, text, image, etc.
You can check if a modal is visible or hidden using the isVisible()
method. You can also programmatically close an open modal by using the close()
or closeModal()
methods. If you happen to use the same set of properties for multiple alert messages during their initialization, you can simply call the setDefaults({configurationObject})
method in the beginning to set the value of all those properties at once. The library also provides a resetDefaults()
method to reset all the properties to their default values.
You can get the title, content, and image of a modal using the getTitle()
, getContent()
, and getImage()
methods. Similarly, you can also get the HTML that makes up the confirm and cancel buttons using the getConfirmButton()
and getCancelButton()
methods.
There are a lot of other methods which can be used to perform other tasks like programmatically clicking on the confirm or cancel buttons.
Final Thoughts
The SweetAlert2 library makes it very easy for developers to create custom alert messages to show to their users by simply setting the values of a few properties. This tutorial was aimed at covering the basics of this library so that you can create your own custom alert messages quickly.
To prevent the post from getting too big, I have only covered the most commonly used methods and properties. If you want to read about all the other methods and properties which can be used to create advanced alert messages, you should go through the detailed documentation of the library.
Don't forget to check out the other JavaScript resources we have available in the Envato Market, as well.
Feel free to let me know if there is anything that you would like me to clarify in this tutorial.
Friday, June 29, 2018
How to Use Implicit Track Sizing on Your CSS Grid
Up until now our CSS grid tutorials have focused largely on explicit values–track sizes which we’ve explicitly defined. We’ve used rows which are 200px high, or perhaps columns which are 1fr wide, and we’ve explicitly stated how many of them we want. But what if we don’t know (or don’t want to commit to) how many tracks we want? That’s where implicit values come into play–let’s take a look.
Starter Grid
Here’s a basic grid which you can fork to follow along. It gives us a grid container, with 9 grid items. No column widths or quantities have been defined yet, so each item fills the maximum width available:
Defining Just One Column
Let’s imagine that we want one column on the left, and that we know exactly how wide we want it: 300px. We can define that by adding grid-template-columns: 300px;
to our grid container. But we won’t be given any other columns unless we explicitly define them:
That is, unless we explicitly say we want one of the grid items to be placed into (for example) column 3 on row 1:
.item-3 { grid-column: 3; grid-row: 1; }
That then gives us extra columns outside our defined grid because CSS Grid will use the available space and its auto-placement algorithm to figure out where everything else goes.
This is great, and Grid will make assumptions even if we want to have more columns, without us having to define each one. But what if we want those implied tracks, however many there are, to have a specific width? That’s where grid-auto-columns
comes into play.
Say “Hello” to grid-auto-columns
If we want all columns besides the first to be 100px wide, we could implicitly state that:
grid-auto-columns: 100px;
Paired with our explicit value, we get the best of both worlds. Here we’re saying that we want the first column to be 1fr
(that it takes up one fraction of whatever space is left–auto
would have the same effect here) and that any other columns after that should be 100px
precisely:
grid-template-columns: 1fr; grid-auto-columns: 100px;
This gives us the following:
And if we state that item 3 should actually be placed in column 5, on row 1, Grid knows how wide to make any additional columns because it’s implied.
We’re not limited to pixel values here either; we could use fraction units, em units, even the minmax()
notation which we’ve discussed in previous tutorials.
Not Forgetting grid-auto-rows
It almost goes without saying that grid-auto-rows
will do the same for rows as grid-auto-columns
does for columns. Here’s an example, where all rows but the first two are fixed at a height of 200px
.
Conclusion
Many of Grid’s properties have default values which will look after you in case you don’t define anything different, but on some occasions we need to at least imply what we want. With implicit track sizing we can imply what size any extra rows or columns should be, if they’re ever needed.
Read More
Thursday, June 28, 2018
Create Interactive Gradient Animations Using Granim.js
Gradients can instantly improve the look and feel of a website, if used carefully with the right color combination. CSS has also come a long way when it comes to applying a gradient on any element and animating it. In this tutorial, we will move away from CSS and create gradient animations using a JavaScript library called Granim.js.
This library draws and animates gradients on a given canvas according to the parameters you set when creating a Granim instance. There are different methods which can be used to make your gradient respond to different user events like a button click. In this tutorial, we will learn about this library in detail and create some simple but nice gradient animation effects.
Create Solid Color Gradient Animations
Before we begin creating any gradient, you will have to include the library in your project. For this, you can either download Granim.js from GitHub or link directly to a CDN. The library version that I am using in this tutorial is 1.1. Some methods that we will discuss here were only added in version 1.1, so using an older library version when following this tutorial will not always give the expected result. Keeping these points in mind, let's create our first gradient using Granim.js.
Every time you create a new Granim instance, you can pass it an object of key-value pairs, where the key is the name of a particular property and the value is the value of the property. The element
property is used to specify the CSS selector or DOM node which will point to the canvas on which you want to apply a particular gradient.
When you create a gradient animation where the colors change from a relatively light value to a darker value, it might become impossible to read some text that you have positioned on the canvas. For example, the initial gradient applied on an element might be a combination of yellow and light green. In such cases, the text of the canvas would have to be darker for users to be able to read it properly.
Similarly, the gradient might consist of dark red and black at some other point, and in such cases the dark text would not be easy to read. Granim.js solves this problem for you by allowing you to specify a container element on which you can add the dark and light classes to style the text or other elements accordingly. The value of the elToSetClassOn
property is set to body
by default, but you can also specify any other container element. The dark and light class names are updated automatically based on the average color of the gradient.
The elToSetClassOn
property does not work by itself. You will also have to specify a name for the Granim
instance that you created using the name property. If you set the name to something like first-gradient
, the name of the classes applied on the container element will become first-gradient-light
or first-gradient-dark
based on how light or dark the gradient currently is. This way, any element which needs to change its color based on the lightness or darkness of the gradient will be able to do so with ease.
The direction in which a gradient should be drawn can be specified using the direction
property. It has four valid values: diagonal
, left-right
, top-bottom
, and radial
. The gradients that you create will not move in those particular directions—they will just be drawn that way. The position of the gradient doesn't change during the animation; only its colors do.
There is also a states
property, which accepts an object as its value. Each state specified inside the states
object will have a name and a set of key-value pairs. You can use the gradients
property to specify different colors which should make up a particular gradient. You can set the value of this property to be equal to an array of gradients.
Granim.js will automatically create an animation where the colors of the gradient change from one set to another. The transition between different gradients takes 5,000 milliseconds by default. However, you can speed up or slow down the animation by setting an appropriate value for the transitionSpeed
property.
After the gradients start animating, they will have to come to an end at one point or another. You can specify if the gradient should then just stop there or start animating again from the beginning using the loop
property. This is set to true
by default, which means that the gradient would keep animating.
Each color in a gradient can have a different opacity, which can be specified using the opacity
property. This property accepts an array to determine how opaque each color is going to be. For two gradient colors, the value can be [0.1, 0.8]. For three gradient colors, the value can be [1, 0.5, 0.75], etc.
You also have the option to specify the time it takes for the gradient animation to go from one state to another using the stateTransitionSpeed
. This is different from the transitionSpeed
property, which controls the animation speed inside the same state.
In the following code snippet, I have created two different Granim
instances to draw different gradients. In the first case, we have only specified a single gradient, so there is not any actual animation and the colors don't change at all.
var firstGranim = new Granim({ element: "#first", name: "first-gradient", direction: "diagonal", opacity: [1, 1], states: { "default-state": { gradients: [["#8BC34A", "#FF9800"]] } } }); var secondGranim = new Granim({ element: "#second", name: "second-gradient", elToSetClassOn: ".wrapper", direction: "top-bottom", opacity: [1, 1], states: { "default-state": { gradients: [["#9C27B0", "#E91E63"], ["#009688", "#8BC34A"]], transitionSpeed: 2000 } } });
Animate Gradients Over an Image
Another common use of the Granim.js library would be to animate a gradient over an image drawn on the canvas. You can specify different properties to control how the image is drawn on the canvas using the image
property. It accepts an object with key-value pairs as its value. You can use the source
property to specify the path from which the library should get the image to draw it on the canvas.
Any image that you draw on the canvas will be drawn so that its center coincides with the center of the canvas. However, you can use the position
property to specify a different position to draw the image. This property accepts an array of two elements as its value. The first element can have the values left
, center
, and right
. The second element can have the values top
, center
, and bottom
.
These properties are generally useful when you know that the size of the canvas and the image won't match. In these situations, you can use this property to specify the part of the image that should appear on the canvas.
If the images and the canvas have different dimensions, you can also stretch the image so that it fits properly inside the canvas. The stretchMode
property also accepts an array of two elements as its value. Three valid values for both these elements are stretch
, stretch-if-smaller
, and stretch-if-larger
.
A gradient with blend mode set to normal
will completely hide the image underneath it. The only way to show an image below a gradient of solid colors would be to choose a different blend mode. You can read about all the possible blend mode values for a canvas on MDN.
I would like to point out that the ability to animate a gradient over an image was only added in version 1.1 of the Granim.js library. So you will have to use any version higher than that if you want this feature to work properly.
var firstGranim = new Granim({ element: "#first", name: "first-gradient", direction: "diagonal", opacity: [1, 1], image: { source: "path/to/rose_image.jpg", position: ["center", "center"], blendingMode: "lighten" }, states: { "default-state": { gradients: [["#8BC34A", "#FF9800"], ["#FF0000", "#000000"]] } } }); var secondGranim = new Granim({ element: "#second", name: "second-gradient", elToSetClassOn: ".wrapper", direction: "top-bottom", opacity: [1, 1], image: { source: "path/to/landscape.jpg", stretchMode: ["stretch", "stretch"], blendingMode: "overlay" }, states: { "default-state": { gradients: [["#9C27B0", "#E91E63"], ["#009688", "#8BC34A"]], transitionSpeed: 2000 } } });
Methods to Control Gradient Animation Playback
Up to this point, we did not have any control over the playback of the gradient animation once it was instantiated. We could not pause/play it or change its state, direction, etc. The Granim.js library has different methods which let you accomplish all these tasks with ease.
You can play or pause any animation using the play()
and pause()
methods. Similarly, you can change the state of the gradient animation using the changeState('state-name')
method. The state-name
here has to be one of the state names that you defined when instantiating the Granim
instance.
More methods were added in version 1.1 which allow you to change the direction and blend mode of an animation on the fly using the changeDirection('direction-name')
and changeBlendingMode('blending-mode-name')
methods.
In the following code snippet, I am using a button click event to call all these methods, but you can use any other event to call them.
var firstGranim = new Granim({ element: "#first", name: "first-gradient", elToSetClassOn: ".wrapper", direction: "top-bottom", opacity: [1, 1], isPausedWhenNotInView: true, image : { source: 'path/to/landscape.jpg', stretchMode: ["stretch", "stretch"], blendingMode: 'overlay' }, states: { "default-state": { gradients: [["#9C27B0", "#E91E63"], ["#009688", "#8BC34A"]], transitionSpeed: 2000 }, "green-state": { gradients: [["#4CAF50", "#CDDC39"], ["#FFEB3B", "#8BC34A"]], transitionSpeed: 2000 }, "red-state": { gradients: [["#E91E63", "#FF5722"], ["#F44336", "#FF9800"]], transitionSpeed: 2000 } } }); $(".play").on("click", function(){ firstGranim.play(); }); $(".pause").on("click", function(){ firstGranim.pause(); }); $(".diagonal").on("click", function(){ firstGranim.changeDirection('diagonal'); }); $(".radial").on("click", function(){ firstGranim.changeDirection('radial'); }); $(".red-state").on("click", function(){ firstGranim.changeState('red-state'); }); $(".green-state").on("click", function(){ firstGranim.changeState('green-state'); }); $(".color-dodge").on("click", function(){ firstGranim.changeBlendingMode('color-dodge'); }); $(".color-burn").on("click", function(){ firstGranim.changeBlendingMode('color-burn'); }); $(".lighten").on("click", function(){ firstGranim.changeBlendingMode('lighten'); }); $(".darken").on("click", function(){ firstGranim.changeBlendingMode('darken'); });
Final Thoughts
In this tutorial, I have covered the basics of the Granim.js library so that you can get started with it as quickly as possible. There are a few other methods and properties that you might find useful when creating these gradient animations. You should read the official documentation in order to read about them all.
If you’re looking for additional JavaScript resources to study or to use in your work, check out what we have available in the Envato Market.
If you have any questions related to this tutorial, feel free to let me know in the comments.
Wednesday, June 27, 2018
Tuesday, June 26, 2018
Monday, June 25, 2018
Sunday, June 24, 2018
Saturday, June 23, 2018
Friday, June 22, 2018
Join the Design & Illustration Instructor Team!
It's that time of year again, we're looking for some new designers to join our always developing team of awesome instructors.
What We're Looking For
Envato Tuts+ has many areas of content, and while we love a variety of avenues, we're specifically looking for instructors to create written content. The topics we're specifically looking for are:
- Photo manipulation
- Product mockups
- Logo design
- Adobe Photoshop
- Procreate
- Affinity Photo
- Sketchbook
Vector Software Gurus:
- Affinity Designer
- Sketch
- Inkscape
Your area of expertise not listed? We never turn a good application down!
You must also be comfortable with the English language. We can proof your content, but we can't rewrite everything for you.
We're looking for content from quick tips to in-depth tutorials. Most of all, we want instructors who can explain themselves clearly and accurately and produce quality end results. Whether you're an expert in Adobe Illustrator, Adobe InDesign, Inkscape, Adobe Photoshop, Sketch or any other design package, we want to hear from you!
We are passionate about diversity and inclusion, this includes design and trends from all corners of the global. If you want to contribute to our ever expanding Global Influences content, please send us a pitch.
If you're wanting to know more, please check out this insightful comment on our previous call for new instructors.
What Do You Get Out of It?
There are many benefits in becoming an Envato Tuts+ Instructor:
- Getting paid for a subject you're passionate about is always rewarding. Depending on the content type and subject, you could be billing thousands per month! We pay $250 USD for a standard length tutorial (around 25-30 steps/images).
- We have in depth guides to help you put together your posts, from formatting to tone to screenshot presentation. So if you're new to tutorial writing, this is a great place to start!
- Get your name out into the community. This is especially good if you're just starting your freelance career.
- If you create assets for Envato Market or Envato Elements, then use this opportunity to help promote your items!
Pitch a Tutorial!
While I can tell you which areas we're specifically looking into, it all comes down to which areas are your strongest and what you feel most confident in teaching. If you are interested in becoming an Envato Tuts+ Instructor, why don't you pitch us an idea? We're looking forward to hearing from you.
Thursday, June 21, 2018
Wednesday, June 20, 2018
Tuesday, June 19, 2018
Monday, June 18, 2018
Saturday, June 16, 2018
Friday, June 15, 2018
Getting Started With the Fabric Python Library
Fabric is a Python library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks. Fabric is very simple and powerful and can help to automate repetitive command-line tasks. This approach can save time by automating your entire workflow.
This tutorial will cover how to use Fabric to integrate with SSH and automate tasks.
Installation
Fabric is best installed via pip:
$ pip install fabric
Getting Started With Fabric
Usage
Below is a simple function demonstrating how to use Fabric.
def welcome(): print("Welcome to getting started with Fabric!")
The program above is then saved as fabfile.py
in your current working directory. The welcome function can be executed with the fab
tool as follows:
$ fab welcome Welcome to getting started with Fabric
Fabric provides the fab command which reads its configuration from a file, fabfile.py
. The file should be in the directory from which the command is run. A standard fabfile contains the functions to be executed on a remote host or a group of remote hosts.
Features
Fabric implements functions which can be used to communicate with remote hosts:
fabric.operations.run()
This operation is used to run a shell command on a remote host.
Examples
run("ls /var/www/") run("ls /home/userx", shell=False) output = run('ls /var/www/mysites'
fabric.operations.get()
This function is used to download file(s) from a remote host. The example below shows how to download a backup from a remote server.
# Downloading a back-up get("/backup/db.bak", "./db.bak")
fabric.operations.put()
This functions uploads file(s) to a remote host. For example:
with cd('/tmp'): put('/path/to/local/test.txt', 'files')
fabric.operations.reboot()
As the name suggests, this function reboots a system server.
# Reboot the remote system reboot()
fabric.operations.sudo()
This function is used to execute commands on a remote host with superuser privileges. Additionally, you can also pass an additional user argument which allows you to run commands as another user other than root.
Example
# Create a directory sudo("mkdir /var/www")
fabric.operations.local()
This function is used to run a command on the local system. An example is:
# Extract the contents of a tar archive local("tar xzvf /tmp/trunk/app.tar.gz") # Remove a file local("rm /tmp/trunk/app.tar.gz")
fabric.operations.prompt()
The function prompts the user with text and returns the input.
Examples
# Simplest form: environment = prompt('Please specify target environment: ') # specify host env_host = prompt('Please specify host:')
fabric.operations.require()
This function is used to check for given keys in a shared environment dict. If not found, the operation is aborted.
SSH Integration
One of the ways developers interact with remote servers besides FTP clients is through SSH. SSH is used to connect to remote servers and do everything from basic configuration to running Git or initiating a web server.
With Fabric, you can perform SSH activities from your local computer.
The example below defines functions that show how to check free disk space and host type. It also defines which host will run the command:
# Import Fabric's API module from fabric.api import run env.hosts = '159.89.39.54' # Set the username env.user = "root" def host_type(): run('uname -s') def diskspace(): run('df') def check(): # check host type host_type() # Check diskspace diskspace()
In order to run this code, you will need to run the following command on the terminal:
fab check
Output
fab check[159.89.39.54] Executing task 'check' [159.89.39.54] run: uname -s [159.89.39.54] Login password for 'root': [159.89.39.54] out: Linux [159.89.39.54] out: [159.89.39.54] run: df [159.89.39.54] out: Filesystem 1K-blocks Used Available Use% Mounted on [159.89.39.54] out: udev 242936 0 242936 0% /dev [159.89.39.54] out: tmpfs 50004 6020 43984 13% /run [159.89.39.54] out: /dev/vda1 20145768 4398716 15730668 22% / [159.89.39.54] out: tmpfs 250012 1004 249008 1% /dev/shm [159.89.39.54] out: tmpfs 5120 0 5120 0% /run/lock [159.89.39.54] out: tmpfs 250012 0 250012 0% /sys/fs/cgroup [159.89.39.54] out: /dev/vda15 106858 3426 103433 4% /boot/efi [159.89.39.54] out: tmpfs 50004 0 50004 0% /run/user/0 [159.89.39.54] out: none 20145768 4398716 15730668 22% /var/lib/docker/aufs/mnt/781d1ce30963c0fa8af93b5679bf96425a0a10039d10be8e745e1a22a9909105 [159.89.39.54] out: shm 65536 0 65536 0% /var/lib/docker/containers/036b6bcd5344f13fdb1fc738752a0850219c7364b1a3386182fead0dd8b7460b/shm [159.89.39.54] out: none 20145768 4398716 15730668 22% /var/lib/docker/aufs/mnt/17934c0fe3ba83e54291c1aebb267a2762ce9de9f70303a65b12f808444dee80 [159.89.39.54] out: shm 65536 0 65536 0% /var/lib/docker/containers/fd90146ad4bcc0407fced5e5fbcede5cdd3cff3e96ae951a88f0779ec9c2e42d/shm [159.89.39.54] out: none 20145768 4398716 15730668 22% /var/lib/docker/aufs/mnt/ba628f525b9f959664980a73d94826907b7df31d54c69554992b3758f4ea2473 [159.89.39.54] out: shm 65536 0 65536 0% /var/lib/docker/containers/dbf34128cafb1a1ee975f56eb7637b1da0bfd3648e64973e8187ec1838e0ea44/shm [159.89.39.54] out: Done. Disconnecting from 159.89.39.54... done.
Automating Tasks
Fabric enables you to run commands on a remote server without needing to log in to the remote server.
Remote execution with Fabric can lead to security threats since it requires an open SSH port, especially on Linux machines.
For instance, let's assume you want to update the system libraries on your remote server. You don't necessarily need to execute the tasks every other time. You can just write a simple fab file which you will run every time you want to execute the tasks.
In this case, you will first import the Fabric API's module:
from fabric.api import *
Define the remote host you want to update:
env.hosts = '159.89.39.54'
Set the username of the remote host:
env.user = "root"
Although it's not recommended, you might need to specify the password to the remote host.
Lastly, define the function that updates the libraries in your remote host.
def update_libs(): """ Update the default OS installation's basic default tools. """ run("apt-get update")
Now that your fab file is ready, all you need to do is execute it as follows:
$ fab update
You should see the following result:
$ fab update [159.89.39.54] Executing task 'update' [159.89.39.54] run: apt-get update [159.89.39.54] Login password for 'root':
If you didn't define the password, you will be prompted for it.
After the program has finished executing the defined commands, you will get the following response, if no errors occur:
$ fab update ............ Disconnecting from 159.89.39.54... done.
Conclusion
This tutorial has covered what is necessary to get started with Fabric locally and on remote hosts. You can now confidently start writing your own scripts for building, monitoring or maintaining remote servers.
Thursday, June 14, 2018
Wednesday, June 13, 2018
Tuesday, June 12, 2018
Monday, June 11, 2018
Creating Stylish and Responsive Progress Bars Using ProgressBar.js
Nothing on the web happens instantly. The only difference is in the time it takes for a process to complete. Some processes can happen in a few milliseconds, while others can take up to several seconds or minutes. For example, you might be editing a very large image uploaded by your users, and this process can take some time. In such cases, it is a good idea to let the visitors know that the website is not stuck somewhere but it is actually working on your image and making some progress.
One of the most common ways to show readers how much a process has progressed is to use progress bars. In this tutorial, you will learn how to use the ProgressBar.js library to create different progress bars with simple and complex shapes.
Creating a Basic Progress Bar
Once you have included the library in your project, creating a progress bar using this library is easy. ProgressBar.js is supported in all major browsers, including IE9+, which means that you can use it in any website you are creating with confidence. You can get the latest version of the library from GitHub or directly use a CDN link to add it in your project.
To avoid any unexpected behavior, please make sure that the container of the progress bar has the same aspect ratio as the progress bar. In the case of a circle, the aspect ratio of the container should be 1:1 because the width will be equal to the height. In the case of a semicircle, the aspect ratio of the container should be 2:1 because the width will be double the height. Similarly, in the case of a simple line, the container should have an aspect ratio of 100:strokeWidth for the line.
When creating progress bars with a line, circle, or semicircle, you can simply use the ProgressBar.Shape()
method to create the progress bar. In this case, the Shape
can be a Circle
, Line
, or SemiCircle
. You can pass two parameters to the Shape()
method. The first parameter is a selector or DOM node to identify the container of the progress bar. The second parameter is an object with key-value pairs which determine the appearance of the progress bar.
You can specify the color of the progress bar using the color
property. Any progress bar that you create will have a dark gray color by default. The thickness of the progress bar can be specified using the strokeWidth
property. You should keep in mind that the width here is not in pixels but in terms of a percentage of the canvas size. For instance, if the canvas is 200px wide, a strokeWidth
value of 5 will create a line which is 10px thick.
Besides the main progress bar, the library also allows you to draw a trailing line which will show readers the path on which the progress bar will move. The color of the trail line can be specified using the trailColor
property, and its width can be specified using the trailWidth
property. Just like strokeWidth
, the trailWidth
property also computes the width in percentage terms.
The total time taken by the progress bar to go from its initial state to its final state can be specified using the duration
property. By default, a progress bar will complete its animation in 800 milliseconds.
You can use the easing
property to specify how a progress bar should move during the animation. All progress bars will move with a linear
speed by default. To make the animation more appealing, you can set this value to something else like easeIn
, easeOut
, easeInOut
, or bounce
.
After specifying the initial parameter values, you can animate the progress bars using the animate()
method. This parameter accepts three parameters. The first parameter is the amount up to which you want to animate the progress line. The two other parameters are optional. The second parameter can be used to override any animation property values that you set during initialization. The third parameter is a callback function to do something else once the animation ends.
In the following example, I have created three different progress bars using all the properties we have discussed so far.
var lineBar = new ProgressBar.Line('#line-container', { color: 'orange', strokeWidth: 2, trailWidth: 0.5 }); lineBar.animate(1, { duration: 1000 }); var circleBar = new ProgressBar.Circle('#circle-container', { color: 'white', strokeWidth: 2, trailWidth: 10, trailColor: 'black', easing: 'easeInOut' }); circleBar.animate(0.75, { duration: 1500 }); var semiBar = new ProgressBar.SemiCircle('#semi-container', { color: 'violet', strokeWidth: 2, trailWidth: 0.5, easing: 'bounce' }); semiBar.animate(1, { duration: 3000 });
Animating Text Values With the Progress Bar
The only thing that changes with the animation of the progress bars in the above example is their length. However, ProgressBar.js also allows you to change other physical attributes like the width and color of the stroking line. In such cases, you will have to specify the initial values for the progress bar inside the from
parameter and the final values inside the to
parameter when initializing the progress bars.
You can also tell the library to create an accompanying text element with the progress bar to show some textual information to your users. The text can be anything from a static value to a numerical value indicating the progress of the animation. The text
parameter will accept an object as its value.
This object can have a value
parameter to specify the initial text to be shown inside the element. You can also provide a class name to be added to the text element using the className
parameter. If you want to apply some inline styles to the text element, you can specify them all as a value of the style
parameter. All the default styles can be removed by setting the value of style
to null
. It is important to remember that the default values only apply if you have not set a custom value for any CSS property inside style
.
The value inside the text element will stay the same during the whole animation if you don't update it yourself. Luckily, ProgressBar.js also provides a step
parameter which can be used to define a function to be called with each animation step. Since this function will be called multiple times each second, you need to be careful with its use and keep the calculations inside it simple.
var lineBar = new ProgressBar.Line("#line-container", { strokeWidth: 4, trailWidth: 0.5, from: { color: "#FF9900" }, to: { color: "#00FF99" }, text: { value: '0', className: 'progress-text', style: { color: 'black', position: 'absolute', top: '-30px', padding: 0, margin: 0, transform: null } }, step: (state, shape) => { shape.path.setAttribute("stroke", state.color); shape.setText(Math.round(shape.value() * 100) + ' %'); } }); lineBar.animate(1, { duration: 4000 }); var circleBar = new ProgressBar.Circle("#circle-container", { color: "white", strokeWidth: 2, trailWidth: 25, trailColor: "black", easing: "easeInOut", from: { color: "#FF9900", width: 1 }, to: { color: "#FF0099", width: 25 }, text: { value: '0', className: 'progress-text', style: { color: 'black', position: 'absolute', top: '45%', left: '42%', padding: 0, margin: 0, transform: null } }, step: (state, shape) => { shape.path.setAttribute("stroke", state.color); shape.path.setAttribute("stroke-width", state.width); shape.setText(Math.round(shape.value() * 100) + ' %'); } }); circleBar.animate(0.75, { duration: 1500 }); var semiBar = new ProgressBar.SemiCircle("#semi-container", { color: "violet", strokeWidth: 2, trailWidth: 8, trailColor: "black", easing: "bounce", from: { color: "#FF0099", width: 1 }, to: { color: "#FF9900", width: 2 }, text: { value: '0', className: 'progress-text', style: { color: 'black', position: 'absolute', top: '45%', left: '50%', padding: 0, margin: 0, transform: null } }, step: (state, shape) => { shape.path.setAttribute("stroke", state.color); shape.path.setAttribute("stroke-width", state.width); shape.setText(Math.round(shape.value() * 100) + ' %'); } }); semiBar.animate(0.75, { duration: 2000 });
Creating Progress Bars With Custom Shapes
Sometimes, you might want to create progress bars with different shapes that match the overall theme of your website. ProgressBar.js allows you to create progress bars with custom shapes using the Path()
method. This method works like Shape()
but provides fewer parameters to customize the progress bar animation. You can still provide a duration
and easing
value for the animation. If you want to animate the color and width of the stroke used for drawing the custom path, you can do so inside the from
and to
parameters.
The library does not provide any way to draw a trail for the custom path, as it did for simple lines and circles. However, you can create the trail yourself fairly easily. In the following example, I have created a triangular progress bar using the Path()
method.
Before writing the JavaScript code, we will have to define our custom SVG path in HTML. Here is the code I used to create a simple triangle:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" width="300" height="300" viewBox="0 0 300 300"> <path d="M 50 50 L 200 100 L 200 300 z" fill="none" stroke="#ddd" stroke-width="1"/> <path id="triangle" d="M 50 50 L 200 100 L 200 300 z" fill="none" stroke="blue" stroke-width="5"/> </svg>
You might have noticed that I created two different path elements. The first path has a light gray color which acts like the trail we saw with simple progress bars in the previous section. The second path is the one that we animate with our code. We have given it an id
which is used to identify it in the JavaScript code below.
var path = new ProgressBar.Path("#triangle", { duration: 6000, from: { color: "#ff0000", width: 2 }, to: { color: "#0099ff", width: 10 }, strokeWidth: 4, easing: "easeInOut", step: (state, shape) => { shape.path.setAttribute("stroke", state.color); shape.path.setAttribute("stroke-width", state.width); } }); path.animate(1);
Final Thoughts
As you saw in this tutorial, ProgressBar.js allows you to easily create different kinds of progress bars with ease. It also gives you the option to animate different attributes of the progress bar like its width and color.
Not only that, but you can also use this library to change the value of an accompanying text element in order to show the progress in textual form. This tutorial covers everything that you need to know to create simple progress bars. However, you can go through the documentation to learn more about the library.
If there is anything that you would like me to clarify in this tutorial, feel free to let me know in the comments.
Keys, Credentials and Storage on Android
In the previous post on Android user data security, we looked at encrypting data via a user-supplied passcode. This tutorial will shift the focus to credential and key storage. I'll begin by introducing account credentials and end with an example of protecting data using the KeyStore.
-
SecurityStoring Data Securely on AndroidCollin Stuart
-
AndroidHow to Secure an Android AppAshraff Hathibelagal
Often when working with a third-party service there will be some form of authentication required. This may be as simple as a /login
endpoint that accepts a username and password. It would seem at first that a simple solution is to build UI that asks the user to log in, then capture and store their login credentials. However, this isn't the best practice because our app shouldn't need to know the credentials for a 3rd party account. Instead, we can use the Account Manager, which delegates handling that sensitive information for us.
Account Manager
The Account Manager is a centralized helper for user account credentials so that your app does not have to deal with passwords directly. It often provides a token in place of the real username and password that can be used to make authenticated requests to a service. An example is when requesting an OAuth2 token. Sometimes all the required information is already stored on the device, and other times the Account Manager will need to call a server for a refreshed token. You may have seen the Accounts section in your device's Settings for various apps. We can get that list of available accounts like this:
AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccounts();
The code will require the android.permission.GET_ACCOUNTS
permission. If you're looking for a specific account, you can find it like this:
AccountManager accountManager = AccountManager.get(this); Account[] accounts = accountManager.getAccountsByType("com.google");
Once you have the account, atoken for the account can be retrievedby calling the getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)
method. The token can then be used to make authenticated API requests to a service. This could be a RESTful API where you pass in a token parameter during an HTTPS request, without having to ever know the user's private account details.
Because each service will have a different way of authenticating and storing the private credentials, the Account Manager provides authenticator modules for a 3rd party service to implement. While Android has implementations for many popular services, it means you can write your own authenticator to handle your app's account authentication and credential storage. This allows you to make sure the credentials are encrypted. Keep in mind, this also means that credentials in the Account Manager that are used by other services may be stored in clear text, making them visible to anyone who has rooted their device.
Instead of simple credentials, there are times when you will need to deal with a key or a certificate for an individual or entity, for example, when a third party sends you a certificate file which you need to keep. The most common scenario is when an app needs to authenticate to a private organization's server. In the next tutorial, we will be looking at using certificates for authentication and secure communications, but I still want to address how to store these items in the meantime. The Keychain API was originally built for that very specific use—installing a private key or certificate pair from a PKCS#12 file.
The Keychain
Introduced in Android 4.0 (API Level 14), the Keychain API deals with key management. Specifically, it works with PrivateKey
and X509Certificate
objects and provides a more secure container than using your app's data storage. That's because permissions for private keys only allow for your own app to access the keys, and only after user authorization. This means that a lock screen must be set up on the device before you can make use of the credential storage. Also, the objects in the keychain may be bound to secure hardware, if available. The code to install a certificate is as follows:
Intent intent = KeyChain.createInstallIntent(); byte[] p12Bytes = //... read from file, such as example.pfx or example.p12... intent.putExtra(KeyChain.EXTRA_PKCS12, p12Bytes); startActivity(intent);
The user will be prompted for a password to access the private key and an option to name the certificate. To retrieve the key, the following code presents UI that lets the user choose from the list of installed keys.
KeyChain.choosePrivateKeyAlias(this, this, new String[]{"RSA"}, null, null, -1, null);
Once the choice is made, a string alias name is returned in the alias(final String alias)
callback where you can access the private key or certificate chain directly.
public class KeychainTest extends Activity implements ..., KeyChainAliasCallback { //... @Override public void alias(final String alias) { Log.e("MyApp", "Alias is " + alias); try { PrivateKey privateKey = KeyChain.getPrivateKey(this, alias); X509Certificate[] certificateChain = KeyChain.getCertificateChain(this, alias); } catch ... } //... }
Armed with that knowledge, let's now see how we can use the credential storage to save your own sensitive data.
The KeyStore
In the previous tutorial, we looked at protecting data via a user-supplied passcode. This kind of setup is good, but app requirements often steer away from having users login each time and remember an additional passcode. That's where the KeyStore API can be used. Since API 1, the KeyStore has been used by the system to store WIFI and VPN credentials. As of 4.3 (API 18), it allows working with your own app-specific asymmetric keys, and in Android M (API 23) it can store an AES symmetric key. So while the API doesn't allow storing sensitive strings directly, these keys can be stored, and then used to encrypt strings.
The benefit to storing a key in the KeyStore is that it allows keys to be operated on without exposing the secret content of that key; key data does not enter the app space. Remember that keys are protected by permissions so that only your app can access them, and they may additionally be secure hardware-backed if the device is capable. This creates a container that makes it more difficult to extract keys from a device.
Generate a New Random Key
So for this example, instead of generating an AES key from a user-supplied passcode, we can auto-generate a random key that will be protected in the KeyStore. We can do this by creating a KeyGenerator
instance, set to the "AndroidKeyStore"
provider.
//Generate a key and store it in the KeyStore final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) //.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled //.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time .setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call .build(); keyGenerator.init(keyGenParameterSpec); keyGenerator.generateKey();
Important parts to look at here are the .setUserAuthenticationRequired(true)
and .setUserAuthenticationValidityDurationSeconds(120)
specifications. These require a lock screen to be set up and lock the key until the user has authenticated. Looking at the documentation for .setUserAuthenticationValidityDurationSeconds()
, you will see that it means the key is only available a certain number of seconds from password authentication, and that passing in -1
requires finger print authentication every time you want to access the key. Enabling the requirement for authentication also has the effect of revoking the key when the user removes or changes the lock screen. Because storing an unprotected key along side the encrypted data is like putting a house key under the doormat, these options attempt to protect the key at rest in the event a device is compromised. An example might be an offline data dump of the device. Without the password being known for the device, that data is rendered useless.
The .setRandomizedEncryptionRequired(true)
option enables the requirement that there is enough randomization (a new random IV each time) so that if the exact same data is encrypted a second time around, that encrypted output will still be different. This prevents an attacker from gaining clues about the ciphertext based on feeding in the same data. Another option to note is setUserAuthenticationValidWhileOnBody(boolean remainsValid)
, which locks the key once the device has detected it is no longer on the person.
Encrypting Data
Now that the key is stored in the KeyStore, we can create a method that encrypts data using the Cipher
object, given the SecretKey
. It will return a HashMap
containing the encrypted data, and a randomized IV that will be needed to decrypt the data. The encrypted data, along with the IV, can then be saved to a file or into the shared preferences.
private HashMap<String, byte[]> encrypt(final byte[] decryptedBytes) { final HashMap<String, byte[]> map = new HashMap<String, byte[]>(); try { //Get the key final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); final SecretKey secretKey = secretKeyEntry.getSecretKey(); //Encrypt data final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); final byte[] ivBytes = cipher.getIV(); final byte[] encryptedBytes = cipher.doFinal(decryptedBytes); map.put("iv", ivBytes); map.put("encrypted", encryptedBytes); } catch (Throwable e) { e.printStackTrace(); } return map; }
Decrypting to a Byte Array
For decryption, the reverse is applied. The Cipher
object is initialized using the DECRYPT_MODE
constant and a decrypted byte[]
array is returned.
private byte[] decrypt(final HashMap<String, byte[]> map) { byte[] decryptedBytes = null; try { //Get the key final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); final SecretKey secretKey = secretKeyEntry.getSecretKey(); //Extract info from map final byte[] encryptedBytes = map.get("encrypted"); final byte[] ivBytes = map.get("iv"); //Decrypt data final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); final GCMParameterSpec spec = new GCMParameterSpec(128, ivBytes); cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); decryptedBytes = cipher.doFinal(encryptedBytes); } catch (Throwable e) { e.printStackTrace(); } return decryptedBytes; }
Testing the Example
We can now test our example!
@TargetApi(Build.VERSION_CODES.M) private void testEncryption() { try { //Generate a key and store it in the KeyStore final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) //.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled //.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time .setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call .build(); keyGenerator.init(keyGenParameterSpec); keyGenerator.generateKey(); //Test final HashMap<String, byte[]> map = encrypt("My very sensitive string!".getBytes("UTF-8")); final byte[] decryptedBytes = decrypt(map); final String decryptedString = new String(decryptedBytes, "UTF-8"); Log.e("MyApp", "The decrypted string is " + decryptedString); } catch (Throwable e) { e.printStackTrace(); } }
Using RSA Asymmetric Keys for Older Devices
This is a good solution to store data for versions M and higher, but what if your app supports earlier versions? While AES symmetric keys are not supported under M, RSA asymmetric keys are. That means we can use RSA keys and encryption to accomplish the same thing. The main difference here is that an asymmetric keypair contains two keys, a private and a public key, where the public key encrypts the data and the private key decrypts it. A KeyPairGeneratorSpec
is passed into the KeyPairGenerator
that is initialized with KEY_ALGORITHM_RSA
and the "AndroidKeyStore"
provider.
private void testPreMEncryption() { try { //Generate a keypair and store it in the KeyStore KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); end.add(Calendar.YEAR, 10); KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this) .setAlias("MyKeyAlias") .setSubject(new X500Principal("CN=MyKeyName, O=Android Authority")) .setSerialNumber(new BigInteger(1024, new Random())) .setStartDate(start.getTime()) .setEndDate(end.getTime()) .setEncryptionRequired() //on API level 18, encrypted at rest, requires lock screen to be set up, changing lock screen removes key .build(); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); keyPairGenerator.initialize(spec); keyPairGenerator.generateKeyPair(); //Encryption test final byte[] encryptedBytes = rsaEncrypt("My secret string!".getBytes("UTF-8")); final byte[] decryptedBytes = rsaDecrypt(encryptedBytes); final String decryptedString = new String(decryptedBytes, "UTF-8"); Log.e("MyApp", "Decrypted string is " + decryptedString); } catch (Throwable e) { e.printStackTrace(); } }
To encrypt, we get the RSAPublicKey
from the keypair and use it with the Cipher
object.
public byte[] rsaEncrypt(final byte[] decryptedBytes) { byte[] encryptedBytes = null; try { final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); final RSAPublicKey publicKey = (RSAPublicKey)privateKeyEntry.getCertificate().getPublicKey(); final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); cipherOutputStream.write(decryptedBytes); cipherOutputStream.close(); encryptedBytes = outputStream.toByteArray(); } catch (Throwable e) { e.printStackTrace(); } return encryptedBytes; }
Decryption is done using the RSAPrivateKey
object.
public byte[] rsaDecrypt(final byte[] encryptedBytes) { byte[] decryptedBytes = null; try { final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); final RSAPrivateKey privateKey = (RSAPrivateKey)privateKeyEntry.getPrivateKey(); final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); cipher.init(Cipher.DECRYPT_MODE, privateKey); final CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(encryptedBytes), cipher); final ArrayList<Byte> arrayList = new ArrayList<>(); int nextByte; while ( (nextByte = cipherInputStream.read()) != -1 ) { arrayList.add((byte)nextByte); } decryptedBytes = new byte[arrayList.size()]; for(int i = 0; i < decryptedBytes.length; i++) { decryptedBytes[i] = arrayList.get(i); } } catch (Throwable e) { e.printStackTrace(); } return decryptedBytes; }
One thing about RSA is that encryption is slower than it is in AES. This is usually fine for small amounts of information such as when you're securing shared preference strings. If you find there is a performance problem encrypting large amounts of data, however, you can instead use this example to encrypt and store just an AES key. Then, use that faster AES encryption that was discussed in the previous tutorial for the rest of your data. You can generate a new AES key and convert it to a byte[]
array that is compatible with this example.
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256); //AES-256 SecretKey secretKey = keyGenerator.generateKey(); byte[] keyBytes = secretKey.getEncoded();
To get the key back from the bytes, do this:
SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
That was a lot of code! To keep all of the examples simple, I have omitted thorough exception handling. But remember that for your production code, it's not recommended to simply catch all Throwable
cases in one catch statement.
Conclusion
This completes the tutorial on working with credentials and keys. Much of the confusion around keys and storage has to do with the evolution of the Android OS, but you can choose which solution to use given the API level your app supports.
Now that we have covered the best practices for securing data at rest, the next tutorial will focus on securing data in transit.
Send Emails in PHP Using the Swift Mailer
In this article, we're going to explore the Swift Mailer library that allows you to send emails from PHP applications. Starting with installation and configuration, we'll go through a real-world example that demonstrates various aspects of sending emails using the Swift Mailer library.
What is Swift Mailer?
When it comes to sending emails in PHP applications, there are plethora of options to choose from. You might even end up creating your own wrapper to setup email features quickly. However, you're always in luck if you're using a well maintained and a feature-rich library.
The Swift Mailer is a popular library for sending emails from PHP applications, and is widely accepted by the PHP community. It's a feature-rich library in the sense that it covers almost every aspect of sending emails: from setting up different transports to customizing the message that's being sent.
In fact, it's a pretty straightforward process to send emails using the Swift Mailer library.
- initialize the Transport (SMTP/Sendmail) object
- initialize the Mailer object with that Transport
- initialize the Message object
- format and send the message
In the next section, we'll go through a real world example to demonstrate each of the aforementioned steps.
Installation And Configuration
In this section, we'll go through installation and configuration of the Swift Mailer library. The instillation is pretty straightforward, as it's already available as a Composer package. Before we go ahead, make sure you've installed the Composer because we'll need it to install the Swift Mailer library.
Once you've installed the Composer, go ahead and grab the Swift Mailer library using the following command.
$composer require "swiftmailer/swiftmailer:^6.0"
With that, the Swift Mailer library should be installed, along with the necessary dependencies in the vendor directory. And the contents of the newly created composer.json should look like this:
{ "require": { "swiftmailer/swiftmailer": "^6.0" } }
So, that's the installation part, but how are you supposed to use it? In fact, it's just a matter of including the autoload.php file created by Composer in your application as shown in the following snippet.
<?php require_once './vendor/autoload.php'; // your application code... ?>
How to Send Mails
In the earlier section, we explored how to install the Swift Mailer library using Composer. In this section, we'll start implementing a real world example.
Go ahead and create the email.php file with the following contents.
<?php require_once './vendor/autoload.php'; try { // Create the SMTP Transport $transport = (new Swift_SmtpTransport('smtp.hostname', 25)) ->setUsername('xxxxxxxx') ->setPassword('xxxxxxxx'); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); // Create a message $message = new Swift_Message(); // Set a "subject" $message->setSubject('Demo message using the SwiftMailer library.'); // Set the "From address" $message->setFrom(['sender@gmail.com' => 'sender name']); // Set the "To address" [Use setTo method for multiple recepients, argument should be array] $message->addTo('recipient@gmail.com','recipient name'); // Add "CC" address [Use setCc method for multiple recepients, argument should be array] $message->addCc('recipient@gmail.com', 'recipient name'); // Add "BCC" address [Use setBcc method for multiple recepients, argument should be array] $message->addBcc('recipient@gmail.com', 'recipient name'); // Add an "Attachment" (Also, the dynamic data can be attached) $attachment = Swift_Attachment::fromPath('example.xls'); $attachment->setFilename('report.xls'); $message->attach($attachment); // Add inline "Image" $inline_attachment = Swift_Image::fromPath('nature.jpg'); $cid = $message->embed($inline_attachment); // Set the plain-text "Body" $message->setBody("This is the plain text body of the message.\nThanks,\nAdmin"); // Set a "Body" $message->addPart('This is the HTML version of the message.<br>Example of inline image:<br><img src="'.$cid.'" width="200" height="200"><br>Thanks,<br>Admin', 'text/html'); // Send the message $result = $mailer->send($message); } catch (Exception $e) { echo $e->getMessage(); }
Let's go through how this code works.
Initialize Swift Mailer
The Swift Mailer library supports different transports like SMTP and Sendmail while sending an email. So, the first thing that you need to do is to initialize the transport
object.
In the above example, I've used the SMTP transport to send mails.
$transport = (new Swift_SmtpTransport('smtp.hostname', 25)) ->setUsername('xxxxxxxx') ->setPassword('xxxxxxxx');
Of course, if you would like to use the Sendmail protocol, you'll need to initialize the corresponding Swift_SendmailTransport
object.
// Create the SendMail Transport $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs');
Once the transport is created, we need to initialize a mailer object and pass the transport that we've created already.
// Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport);
Create a Message
After creating the transport and mailer objects, the only remaining thing is to instantiate the Swift_Message
object and decorate it with necessary attributes.
// Create a message $message = new Swift_Message();
Now, we'll use the $message
object to prepare contents of our message. To start with, the setSubject
method allows you to set the subject of the email.
// Set a "subject" $message->setSubject('Demo message using the SwiftMailer library.');
The setFrom
method is used to set the from address of the email.
// Set the "From address" $message->setFrom(['sender@gmail.com' => 'Sender Name']);
Moving ahead, let's set the To address of the email. In fact, there are couple of variations for setting recipients of the email. If you want to set a single recipient, you can use the addTo
method and the setTo
method on the other end is used to set multiple recipients.
// Set the "To address" [Use setTo method for multiple recepients, argument should be array] $message->addTo('recipient@gmail.com','receiver name');
The addCc
and addBcc
methods are used to set the CC and BCC addresses of the email respectively.
// Add "CC" address [Use setCc method for multiple recepients, argument should be array] $message->addCc('recipient@gmail.com', 'recipient name'); // Add "BCC" address [Use setBcc method for multiple recepients, argument should be array] $message->addBcc('recipient@gmail.com', 'recipient name');
Attaching Files
Next, let's have a look at how you can attach a file to an email.
You first need to instantiate the Swift_Attachment
object with a valid filename. After creating the attachment object, you can add it to the email with the attach
method. Also, you can use the setFilename
method if you want to change the filename that will appear in the message attachment.
// Add an "Attachment" (Also, the dynamic data can be attached) $attachment = Swift_Attachment::fromPath('example.xls'); $attachment->setFilename('report.xls'); $message->attach($attachment);
Along with regular file attachments, sometimes you want to embed images in the message text. You can do that by using the embed
method as shown in the following snippet. The embed
method returns the unique ID of the embedded object, which you can use later on in the message while referencing the image via src
property.
// Add inline "Image" $inline_attachment = Swift_Image::fromPath('nature.jpg'); $cid = $message->embed($inline_attachment);
The Message Body
Next, let's set the email body by using the setBody
method.
// Set the plain-text "Body" $message->setBody("This is the plain text body of the message.\nThanks,\nAdmin");
If you want to set the HTML version of the message, you can use the addPart
method as shown in the following snippet. As you can see, we're using $cid
to reference the image we embedded earlier.
// Set a "Body" $message->addPart('This is the HTML version of the message.<br>Example of inline image:<br><img src="'.$cid.'" width="200" height="200"><br>Thanks,<br>Admin', 'text/html');
Send the Message!
Finally, we'll use the send
method of the Mailer object to send the email.
// Send the message $result = $mailer->send($message);
Try running the script, and you should receive an email! Let me know in the comment section if you face any issues.
Conclusion
Today, we looked at one of the most popular PHP libraries for sending emails: Swift Mailer. With this library, you can effortlessly send emails from your PHP scripts.
Feel free to post your thoughts and queries using the form below.
Sunday, June 10, 2018
Saturday, June 9, 2018
Friday, June 8, 2018
Set Up an OAuth2 Server Using Passport in Laravel
In this article, we’re going to explore how you could set up a fully fledged OAuth2 server in Laravel using the Laravel Passport library. We’ll go through the necessary server configurations along with a real-world example to demonstrate how you could consume OAuth2 APIs.
I assume that you’re familiar with the basic OAuth2 concepts and flow as we’re going to discuss them in the context of Laravel. In fact, the Laravel Passport library makes it pretty easy to quickly set up an OAuth2 server in your application. Thus, other third-party applications are able to consume APIs provided by your application.
In the first half of the article, we’ll install and configure the necessary libraries, and the second half goes through how to set up demo resources in your application and consume them from third-party applications.
Server Configurations
In this section, we're going to install the dependencies that are required in order to make the Passport library work with Laravel. After installation, there's quite a bit of configuration that we'll need to go through so that Laravel can detect the Passport library.
Let's go ahead and install the Passport library using composer.
$composer require laravel/passport
That's pretty much it as far as the Passport library installation is concerned. Now let's make sure that Laravel knows about it.
Working with Laravel, you're probably aware of the concept of a service provider that allows you to configure services in your application. Thus, whenever you want to enable a new service in your Laravel application, you just need to add an associated service provider entry in the config/app.php
.
If you're not aware of Laravel service providers yet, I would strongly recommend that you do yourself a favor and go through this introductory article that explains the basics of service providers in Laravel.
In our case, we just need to add the PassportServiceProvider
provider to the list of service providers in config/app.php
as shown in the following snippet.
... ... 'providers' => [ /* * Laravel Framework Service Providers... */ Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Notifications\NotificationServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, /* * Package Service Providers... */ Laravel\Tinker\TinkerServiceProvider::class, /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, Laravel\Passport\PassportServiceProvider::class, ], ... ...
Next, we need to run the migrate
artisan command, which creates the necessary tables in a database for the Passport library.
$php artisan migrate
To be precise, it creates following the tables in the database.
oauth_access_tokens oauth_auth_codes oauth_clients oauth_personal_access_clients oauth_refresh_tokens
Next, we need to generate a pair of public and private keys that will be used by the Passport library for encryption. As expected, the Passport library provides an artisan command to create it easily.
$php artisan passport:install
That should have created keys at storage/oauth-public.key
and storage/oauth-private.key
. It also creates some demo client credentials that we'll get back to later.
Moving ahead, let's oauthify the existing User model class that Laravel uses for authentication. To do that, we need to add the HasApiTokens
trait to the User
model class. Let's do that as shown in the following snippet.
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Laravel\Passport\HasApiTokens; class User extends Authenticatable { use HasApiTokens; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; }
The HasApiTokens
trait contains helper methods that are used to validate tokens in the request and check the scope of resources being requested in the context of the currently authenticated user.
Further, we need to register the routes provided by the Passport library with our Laravel application. These routes will be used for standard OAuth2 operations like authorization, requesting access tokens, and the like.
In the boot method of the app/Providers/AuthServiceProvider.php
file, let's register the routes of the Passport library.
... ... /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Passport::routes(); } ... ...
Last but not least, we need to change the api
driver from token to passport in the config/auth.php
file, as we're going to use the Passport library for the API authentication.
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ],
So far, we've done everything that's required as far as the OAuth2 server configuration is concerned.
Set Up the Demo Resources
In the previous section, we did all the hard work to set up the OAuth2 authentication server in our application. In this section, we'll set up a demo resource that could be requested over the API call.
We will try to keep things simple. Our demo resource returns the user information provided that there's a valid uid
parameter present in the GET
request.
Let's create a controller file app/Http/Controllers/UserController.php
with the following contents.
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\User; class UserController extends Controller { public function get(Request $request) { $user_id = $request->get("uid", 0); $user = User::find($user_id); return $user; } }
As usual, you need to add an associated route as well, which you are supposed to add in the routes/web.php
file. But what we are talking about is the API route, and thus it needs special treatment.
The API routes are defined in the routes/api.php
file. So, let's go ahead and add our custom API route as shown in the following snippet.
<?php use Illuminate\Http\Request; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); // custom API route Route::middleware('auth:api')->get('/user/get', 'UserController@get');
Although we've defined it as /user/get
, the effective API route is /api/user/get
, and that's what you should use when you request a resource over that route. The api
prefix is automatically handled by Laravel, and you don't need to worry about that!
In the next and last section, we'll discuss how you could create client credentials and consume the OAuth2 API.
How to Consume OAuth2 APIs
Now that we've set up the OAuth2 server in our application, any third party can connect to our server with OAuth and consume the APIs available in our application.
First of all, third-party applications must register with our application in order to be able to consume APIs. In other words, they are considered as client applications, and they will receive a client id and client secret upon registration.
The Passport library provides an artisan command to create client accounts without much hassle. Let's go ahead and create a demo client account.
$php artisan passport:client Which user ID should the client be assigned to?: > 1 What should we name the client?: > Demo OAuth2 Client Account Where should we redirect the request after authorization? [http://localhost/auth/callback]: > http://localhost/oauth2_client/callback.php New client created successfully. Client ID: 1 Client secret: zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01
When you run the artisan passport:client
command, it asks you a few questions before creating the client account. Out of those, there's an important one that asks you the callback URL
.
The callback URL
is the one where users will be redirected back to the third-party end after authorization. And that's where the authorization code that is supposed to be used in exchange for the access token will be sent. We are about to create that file in a moment.
Now, we're ready to test OAuth2 APIs in the Laravel application.
For demonstration purposes, I'll create the oauth2_client
directory under the document root in the first place. Ideally, these files will be located at the third-party end that wants to consume APIs in our Laravel application.
Let's create the oauth2_client/auth_redirection.php
file with the following contents.
<?php $query = http_build_query(array( 'client_id' => '1', 'redirect_uri' => 'http://localhost/oauth2_client/callback.php', 'response_type' => 'code', 'scope' => '', )); header('Location: http://your-laravel-site-url/oauth/authorize?'.$query);
Make sure to change the client_id
and redirect_uri
parameters to reflect your own settings—the ones that you used while creating the demo client account.
Next, let's create the oauth2_client/callback.php
file with the following contents.
<?php // check if the response includes authorization_code if (isset($_REQUEST['code']) && $_REQUEST['code']) { $ch = curl_init(); $url = 'http://your-laravel-site-url/oauth/token'; $params = array( 'grant_type' => 'authorization_code', 'client_id' => '1', 'client_secret' => 'zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01', 'redirect_uri' => 'http://localhost/oauth2_client/callback.php', 'code' => $_REQUEST['code'] ); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $params_string = ''; if (is_array($params) && count($params)) { foreach($params as $key=>$value) { $params_string .= $key.'='.$value.'&'; } rtrim($params_string, '&'); curl_setopt($ch,CURLOPT_POST, count($params)); curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string); } $result = curl_exec($ch); curl_close($ch); $response = json_decode($result); // check if the response includes access_token if (isset($response->access_token) && $response->access_token) { // you would like to store the access_token in the session though... $access_token = $response->access_token; // use above token to make further api calls in this session or until the access token expires $ch = curl_init(); $url = 'http://your-laravel-site-url/api/user/get'; $header = array( 'Authorization: Bearer '. $access_token ); $query = http_build_query(array('uid' => '1')); curl_setopt($ch,CURLOPT_URL, $url . '?' . $query); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); $result = curl_exec($ch); curl_close($ch); $response = json_decode($result); var_dump($result); } else { // for some reason, the access_token was not available // debugging goes here } }
Again, make sure to adjust the URLs and client credentials according to your setup in the above file.
How It Works Altogether
In this section, we'll test it altogether from the perspective of an end user. As an end user, there are two applications in front of you:
- The first one is the Laravel application that you already have an account with. It holds your information that you could share with other third-party applications.
- The second one is the demo third-party client application,
auth_redirection.php
andcallback.php
, that wants to fetch your information from the Laravel application using the OAuth API.
The flow starts from the third-party client application. Go ahead and open the http://localhost/oauth2_client/auth_redirection.php URL in your browser, and that should redirect you to the Laravel application. If you're not already logged into the Laravel application, the application will ask you to do so in the first place.
Once the user is logged in, the application displays the authorization page.
If the user authorizes that request, the user will be redirected back to the third-party client application at http://localhost/oauth2_client/callback.php along with the code
as the GET
parameter that contains the authorization code.
Once the third-party application receives the authorization code, it could exchange that code with the Laravel application to get the access token. And that's exactly what it has done in the following snippet of the oauth2_client/callback.php
file.
$ch = curl_init(); $url = 'http://your-laravel-site-url/oauth/token'; $params = array( 'grant_type' => 'authorization_code', 'client_id' => '1', 'client_secret' => 'zMm0tQ9Cp7LbjK3QTgPy1pssoT1X0u7sg0YWUW01', 'redirect_uri' => 'http://localhost/oauth2_client/callback.php', 'code' => $_REQUEST['code'] ); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $params_string = ''; if (is_array($params) && count($params)) { foreach($params as $key=>$value) { $params_string .= $key.'='.$value.'&'; } rtrim($params_string, '&'); curl_setopt($ch,CURLOPT_POST, count($params)); curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string); } $result = curl_exec($ch); curl_close($ch); $response = json_decode($result);
Next, the third-party application checks the response of the CURL request to see if it contains a valid access token in the first place.
As soon as the third-party application gets the access token, it could use that token to make further API calls to request resources as needed from the Laravel application. Of course, the access token needs to be passed in every request that's requesting resources from the Laravel application.
We've tried to mimic the use-case in that the third-party application wants to access the user information from the Laravel application. And we've already built an API endpoint, http://your-laravel-site-url/api/user/get, in the Laravel application that facilitates it.
// check if the response includes access_token if (isset($response->access_token) && $response->access_token) { // you would like to store the access_token in the session though... $access_token = $response->access_token; // use above token to make further api calls in this session or until the access token expires $ch = curl_init(); $url = 'http://your-laravel-site-url/api/user/get'; $header = array( 'Authorization: Bearer '. $access_token ); $query = http_build_query(array('uid' => '1')); curl_setopt($ch,CURLOPT_URL, $url . '?' . $query); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); $result = curl_exec($ch); curl_close($ch); $response = json_decode($result); var_dump($result); }
So that's the complete flow of how you're supposed to consume the OAuth2 APIs in Laravel.
And with that, we’ve reached the end of this article.
Conclusion
Today, we explored the Passport library in Laravel, which allows us to set up an OAuth2 server in an application very easily.
For those of you who are either just getting started with Laravel or looking to expand your knowledge, site, or application with extensions, we have a variety of things you can study in Envato Market.
Don't hesitate to share your thoughts and queries using the feed below!