Category Archives: Web Development

Implementing the OAUTH 2.0 flow in app for office sandboxed environment

EDIT: this approach is outdated. You can have a look at the sample we released and especially in the README section we compare the different approaches
https://github.com/Keluro/Office365-AddinWeb-SignInSample

In this post I will explain how I implemented the OAUTH 2.0 flow in the app for office sandboxed environment. The objective of this post is to discuss with others if the proposed implementation is satisfactory. Do not hesitate to criticize and propose alternatives.

Following the msdn documentation, the app for office model is the new model for

engaging new consumer and enterprise experiences for Office client applications. Using the power of the web and standard web technologies like HTML5, XML, CSS3, JavaScript, and REST APIs, you can create apps that interact with Office documents, email messages, meeting requests, and appointments.

Personally, I find this extremely promising, I even release my first app last year: Keluro web analytics that is distributed here on the store. I even wrote a small article dealing with app for office on the Keluro web blog.

Let us get straight to the point for this tech article. Apps for office aim at building connected service. For example, Keluro web analytics fetchs data from Google Analytics within MS Excel. I am working on a new project that must communicate with other Office 365 APIs. In all cases, you must use the OAUTH 2.0 flow to grant your app the right to communicate with those APIs. Sometimes there are some client libraries to leverage technicalities of the OAUTH flow. For my fist app, I used the Google Javascript API and for the second one I used the Azure Active Directory adal.js library.

However, there is problem. The apps for office run in a sandboxed environment that prevent cross domain navigation. This sandboxed environment is an iframe with sandbox attributes for the case of the office web apps. I asked the question for more information in this msdn thread. In all cases, the consequence is that the usual OAUTH 2.0 flow that redirects you to https://login.microsoft.com/etc. or https://apis.google.com to prompt the user for allowing access will not work. In addition, the pages served by those domains cannot be ‘iframed’ whether they are served to with X-Frame-Options deny or some js ‘frame busting’ is embedded.

I will get straight to the only working solution that I found. Actually, its the same recipe that I used for Google APIs and ADAL.

It looks like that the apps for office run with the following sandboxed attributes sandbox=”allow-scripts allow-forms allow-same-origin ms-allow-popups allow-popups”. Therefore, we are allowed to use popups and this popup is not restricted by CrossOrigin. What we will do is to open a popup and we will do the OAUTH flow in this popup, when its done we will get back the necessary information in the main app iframe. Here is a summary with a small graphic.

An overview of the solution found for the OAUTH2.0 in sandboxed env

An overview of the solution found for the OAUTH2.0 in sandboxed env

Then, you got it we will use a special callback.html file (that is basically blank and contains only javascript) as returned url. Here it its code.

<!--usual html5 doctype and meta-->
<body>
    <div id="oauthurl"></div>
     <script>
        var closeWindowCheck = function () {
        <!--transmit the hash of the return url to the parent iframe-->
            window.oauthHash =  location.hash;
            <!-- wait that the parent window give its approbation to close-->
            if (window.canclosewindow === true) { 
                window.close();
            }
        }
        var interval = setInterval(closeWindowCheck, 200);
    </script>
</body>
</html>

Then in the main iframe when it’s time to start the OAUTH flow, you have a piece of javascript that looks like the following

//this javascript lives in the sandboxed environment
//urlNavigate is the oauth2.0 url of the apis you are targeting with the parameters
//use callback.html as redirect uri.
var childWindow =window.open(urlNavigate,'Auth window', 'height=500,width=500');
var interval;
var pollChildWindow = function () {
    if (childWindow.closed === false) {
        var oauthHash;
        try {
           //this throws exception until the popup returns to
           //callback.html served in our domain.
            oauthHash = childWindow.oauthHash; 
        }catch(ex){}

        if (typeof oauthHash === &quot;string&quot;) {
            //childWindow.close(); // does not work with Chrome
            // ->; that is why we have the setInterval in callback.html javascript
            childWindow.canclosewindow = true; // allow the child window to close.
            var startWith = oauthHash.indexOf('#id_token');
            var currentRef = window.location.href.split('#')[0];
            //you get the id_token and other information from OAUTH2.0 
            //do whatever you have to do with it in your app.
            //YOUR LOGIC HERE
        }
    } else {
        clearInterval(interval);
    }
};                                                                                                                                          
interval = setInterval(pollChildWindow, 200);

I personally find this implementation not satisfactory because of the use of the popup (that may be blocked). What do you think of it ? Do you think of an alternative. I tried many things using postMessage API but it does not work with IE in sandboxed environment.

This is the implementation that is discussed in this ADAL.js issue. You may also find a setup of a sandboxed environment and some implementation attempt (without apps for office for simplicity) on my remote branch of my Adal.js fork.

Resize image and preserve ratio with Powershell

My recently created company website Keluro has two blogs: one in french and one in english. The main blog pages are a preview list of the existing posts. I gave the possibility to the writer to put a thumbnail image in the preview. It’s a simply <img /> tag where a css class is responsible for the resizing and to display the image in a 194px X 194px box while keeping the original aspect ratio. Most of the time this preview is a reduction of an image that is displayed in the blog post. Everything was fine until I found out that the these blog pages did not received a good mark while inspecting them with PageSpeedInsights . It basically says that the thumbnails were not optimized enough… For SEO reasons I want these blog pages to load quickly so I needed to resize these images once for all even if it has to duplicate the image.

Resizing and keeping aspect ratio

Resizing two pictures with landscape and portrait aspect ratio to make them fill a given canvas.

I think that most of us already had to do such kind of image resizing task. You can use many available software to do that: Paint, Office Picture Manager, Gimp, Inkscape etc. However, when it comes to manipulate many pictures, it could be really useful to use a script. Let me share with you this Powershell script that you can use to resize your .jpg pictures. Note that there is also a quality parameter (from 1 to 100) that you can use if you need to compress more the image.

Param ( [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageSource,
[Parameter(Mandatory=$True)] [ValidateNotNull()] $imageTarget,
[Parameter(Mandatory=$true)][ValidateNotNull()] $quality )

if (!(Test-Path $imageSource)){throw( "Cannot find the source image")}
if(!([System.IO.Path]::IsPathRooted($imageSource))){throw("please enter a full path for your source path")}
if(!([System.IO.Path]::IsPathRooted($imageTarget))){throw("please enter a full path for your target path";)}
if ($quality -lt 0 -or $quality -gt 100){throw( "quality must be between 0 and 100.")}

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$bmp = [System.Drawing.Image]::FromFile($imageSource)

#hardcoded canvas size...
$canvasWidth = 194.0
$canvasHeight = 194.0

#Encoder parameter for image quality
$myEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
# get codec
$myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}

#compute the final ratio to use
$ratioX = $canvasWidth / $bmp.Width;
$ratioY = $canvasHeight / $bmp.Height;
$ratio = $ratioY
if($ratioX -le $ratioY){
  $ratio = $ratioX
}

#create resized bitmap
$newWidth = [int] ($bmp.Width*$ratio)
$newHeight = [int] ($bmp.Height*$ratio)
$bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
$graph = [System.Drawing.Graphics]::FromImage($bmpResized)

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)

#save to file
$bmpResized.Save($imageTarget,$myImageCodecInfo, $($encoderParams))
$graph.Dispose()
$bmpResized.Dispose()
$bmp.Dispose()

Now suppose that you have saved and named the script above “MakePreviewImages.ps1”. You may use it in a loop statement such as the following one where we assume that MakePreviewImages.ps1 is located under the current directory and the images are in a subfolder called “images”.

Get-ChildItem .images -Recurse -Include *.jpg | Foreach-Object{
   $newName = $_.FullName.Substring(0, $_.FullName.Length - 4) + "_resized.jpg"
     ./MakePreviewImages.ps1 $_.FullName $newName 75
   }

Organize a multilanguage Jekyll site

In this post I will describe a simple organization of Jekyll sources to get a mulitlanguage website.

EDIT: In the post below I suggest to use a ‘translated’ tree structure under the /fr directory. e.g. /about/about.html becomes fr/apropos/apropos.html. This leads to complication and nobody cares if the url is translated. I suggest you to keep the exact same tree structure in base site, _layout and fr directories.

What is Jekyll actually? Jekyll describes itself as a “a blog-aware static site generator”. If you know the product you’ll find this description totally fitted but still obscure if you are a newcomer. Let me introduce Jekyll in my own terms. Jekyll helps you to build .html pages, they are created when you publish (or update your site). Contrary to traditional dynamic webservers (e.g. ASP.NET, PHP etc.), the pages are not served and created “on demand” when the user visits the website. With Jekyll it’s more simple, they are only web pages stored on the server disk as if you have created them “by hand”. The magic lies in the fact that you do not have to duplicate all the html everywhere. Jekyll is a “generator” which means by using its basic features, includes, layouts etc. you will not have to repeat yourself so your site will be easily maintainable. What does “blog aware” mean? Jekyll can create pages but it has also been created for blogging on the first place. On its core you will find many things related to blog matters such as pagination, ordering, tagging etc. To conclude the presentation of Jekyll let us mention the fact that it is supported natively by github-pages.

The multi language organization described in this post will illustrate some of the features of Jekyll. If you create a website with Jekyll, you must have a clean website structure such as the following one. You will notice the usual directories _layout and _site.


├── _config.yml
├── _layouts
|    ├── default.html
|    └── post.html
├── _site
|    └── ...
└── index.html

_layout is extremely powerful, it is a form of inheritance. When you declare a page such as index.html and if you reference in the YAML (a kind of file header recognized by Jekyll) the default layout then your page will use all the html defined in the _layout default. We will use extensively the layout pattern for our localized website structure. The main idea is simple: the content of the pages are stored in a layout file located under the _layout directory, the rest of the site will only “call” layouts with the proper language to use.

Let us take a simple example to illustrate this. Suppose that your have a website which default language is english and another one: french. Naturally, the default language is located at the root of the website while other languages are located on a subfolders (e.g. www.myexample.com/fr). Suppose now that you have another subdirectory “about” (“à propos” in french) then your hosted website will have the following structure:


├── fr
|    ├── à propos
|    |    └── apropos.html
|    └── bonjour.html
├── about
|    └──about.html
└── hello.html

The question now is: how to achieve this easily with Jekyll such that the translation of the sentences are kept side by side on the same file? This latter requirement is important to work with your translators. The trick is to replicate the website structure in _layouts. We use the YAML formatter to define a key/value variable that will hold the translation. The “true” pages will only call the layout with the right language to use.

Then, for the example mentioned above, the Jekyll sources structure looks like:


├── _site
|    └── ...
├── _layouts
|    ├── about
|    |    └──about_lyt.html
|    └── hello_lyt.html
├── fr
|    ├── à propos
|    |    └── apropos.html
|    └── bonjour.html
├── about
|    └──about.html
└── hello.html

The about_lyt.html contains the html content of the page and the translation such as this one. This new layout uses the default layout containing the common content of all website pages.


---
layout: default
t:
first:
en: "This is my first sentence"
fr: "C'est ma première phrase"
second:
en: "My second sentence"
fr: "Ma deuxième phrase"
third:
en: "Last sentence"
fr: "Dernière phrase"
---
<div>
<ul>
<li>t.first[page.lang]</li>
<li>t.second[page.lang]</li>
<li>t.third[page.lang]</li>
</ul>
</div>

Then the two localized files simply contain a very basic YAML header.
Let us have a look at the file about.html

---
layout: about/about_lyt
title: "about"
lang: en
---

And now let us examine its french alter ego apropos.html

---
layout: about/about_lyt
title: "A propos"
lang: fr
---

This, organization is very simple and maintainable, this is the one that I have chosen for my own company’s website www.keluro.com. It is also very easy to send the YAML to the translators and put them back in your files to update your website. If you are interested in a script to extract YAML you may use this one written in powershell.