Monday, 21 December 2015

A way to recover your lost Android keystore and key password

I'm pretty good with passwords - I keep a Keepass file on everything I do, and it's backed up immediately to the cloud. But something went wrong recently, and a password to a keystore and key did not get saved to my Keepass file. After some mild panic I learned that you can probably find your passwords in clear text in one of your gradle logfiles, this one to be precise:
.gradle/X.X.X/taskArtifacts/taskArtifacts.bin
Just search for the word password and if you're lucky like me you'll find the strings, separately recorded as keyPassword and storePassword. Sounds like a security hole to me, but boy it came in handy today.

Friday, 18 December 2015

Rendering transaction data in Adestra MessageFocus

I found myself doing this today, and it didn't go without some problems. I thought I'd document the outcome. Here's the data we're sending to the API: and here's the rendering logic in the email:
[*transaction.customer_first_name*] [*transaction.customer_last_name*]
[*transaction.customer_loyalty_card_number*]

[*transaction.customer_loyalty_card_balance*]

[*transaction.order_reference*]

[*transaction.order_total*]

[*transaction.order_store_address*]

[*transaction.order_collect_date*]

[*transaction.order_collect_time*]

[*transaction.till_type*]

[*transaction.address*]

[*transaction.vat_number*]

[*FOREACH item IN transaction.items*]
Name: [*item.value.Name*]
[*FOREACH subitem IN item.value*]
[*subitem.key*]:[*subitem.value*]
[*END*]
[*END*]

Friday, 4 December 2015

Target iPhone only in Cordova

Just drop this into your config.xml:

<preference name="target-device" value="handset" />

Wednesday, 11 November 2015

A potentially dangerous Request.Form value was detected from the client. MVC

From MVC3 onwards if you see this message

A potentially dangerous Request.Form value was detected from the clien

you can fix it by decorating the model propery with this:

[AllowHtml]

Thursday, 5 November 2015

Xcode bypass App Transport Security

During development it's common that we need to access resources within an iOS app from a non-secure server. To enable this we need to bypass Apple's new App Transport Security. We can do this by adding the following to the info.plist file:

<key>NSAppTransportSecurity</key>
    <dict>
      <key>NSExceptionDomains</key>
      <dict>
        <key>mydomain.co.uk</key>
        <dict>
          <key>NSIncludesSubdomains</key>
          <true/>
          <key>NSExceptionAllowsInsecureHTTPLoads</key>
          <true/>
          <key>NSExceptionRequiresForwardSecrecy</key>
          <true/>
          <key>NSExceptionMinimumTLSVersion</key>
          <string>TLSv1.2</string>
          <key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
          <false/>
          <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
          <true/>
          <key>NSThirdPartyExceptionMinimumTLSVersion</key>
          <string>TLSv1.2</string>
          <key>NSRequiresCertificateTransparency</key>
          <false/>
        </dict>
      </dict>
    </dict>

Wednesday, 14 October 2015

Testing Apple Push APNS

Today I've been trying to get some .net code working on a server using PushSharp to send messages via APNS. I've used this code before and it all works fine, and is still in production for a major app, running every ten minutes. For some reason my new cut of the code wasn't working, and I needed some way to work out whether something was wrong with this implementation or perhaps something was wrong with the Device Token I was sending to APNS.

Enter Pusher, an app that runs on your Mac and allows you to fire messages to devices from your desktop either via the sandbox or production server.

This proved to be very useful as within ten minutes I'd established that it was my device token at fault - it seems in that even in my dev environment running my app on my phone from Xcode I was interacting with the Production APNS system rather than the expected sandbox system, and so when sending we should have been using the production certificate.

Tuesday, 13 October 2015

Disabling webview bouncey overscroll in Cordova

To stop the whole app being subject to a bouncy overscroll just ensure these are in your config.xml :

 <preference name="webviewbounce" value="false" />
 <preference name="DisallowOverscroll" value="true" />

Tuesday, 29 September 2015

Adding WinMerge as your merge tool in SourceTree

Set the merge tool to custom and use this command:
C:\Program Files (x86)\WinMerge\WinMergeU.exe
With these arguments:
-e -u -dl "Mine" -wr -dr "Theirs" $LOCAL $REMOTE $MERGED
Taken from this SO answer

Wednesday, 23 September 2015

Cordova WP8 System.SystemException Microsoft.Phone.Interop.ni.dll

I just lost hours diagnosing the following error:

CordovaBrowser_LoadCompleted Apache Cordova native platform version 3.8.1 is starting Exception thrown: 'System.SystemException' in Microsoft.Phone.Interop.ni.dll

I replaced 'execScript' with 'eval' where Browser.InvokeScript was called, as suggested here. This didn't make things better. I also replaced the XHRHelper code with code written by Marius Seimanovs, as suggested here. No joy. I removed all my plugins. Still no dice.

So I setup a new blank WP8 cordova project and worked backwards, trying to break it by introducing my own pre-existing code that was already working in iOS, Android and locally on a Win machine.

I discovered that I had a poorly formatted Content-Security-Policy meta tag. That's all it was! I'd missed off the closing quote from the content attribute, and this brought it all crashing down.

The missing quote!

Wednesday, 16 September 2015

iOS and Android build numbers in Cordova

If you want control over your build numbers for iOS and Android you can do it in your config file like this:



Wednesday, 9 September 2015

Umbraco current culture in Ajax calls

When making an ajax call in Umbraco current culture may be lost, and access to things like dictionary items on a multilingual site becomes a problem. I fixed this like so in the controller method handling the ajax:

System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(GetCurrentCulture());

Where GetCurrentculture simply gets the lcid culture value from session, which is set in on void Session_Start(object sender, EventArgs e) in Global.asax using:

System.Threading.Thread.CurrentThread.CurrentUICulture.LCID

Friday, 4 September 2015

Chrome session cookies with apps running in background

I just discovered something about session cookies in Chrome, after seeing some behaviour one wouldn’t expect.

A by-product of the setting shown below is that session cookies remain active even when all instances of the browser are closed. They are only lost if the user signs out (rather than switch user) or restarts. 

I had this setting checked and I believe it is on by default for all users with apps, because I never specifically chose it:


Wednesday, 5 August 2015

Umbraco Lucene Examine search in foreign languages

Today I had to implement search using Lucene/Examine on a German Umbraco site. It wasn't easy working out what to do, so here's the lowdown, for future reference.

 I installed Lucene.Net.Contrib using the Nuget Package Manager console:
PM> Install-Package Lucene.Net.Contrib -Version 2.9.4.1
Then I updated the index providers in the ExamineSettings.config file, like this example:
<add name="InternalIndexer" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine"
           supportUnpublished="true"
           supportProtected="true"
           analyzer="Lucene.Net.Analysis.De.GermanAnalyzer, Lucene.Net.Contrib.Analyzers"/>
Then, re-index the whole site.

Umbraco Lucene search without case sensitivity

I've been working on a new site build in a small team, using Umbraco 7. My task today was to implement site search, and in doing so I had a problem with case sensitivity - searching for "word" did not return results containing "Word". After some investigation it turned out we were using the WhiteSpaceAnalyzer for the indexing. Switching to the StandardAnalyzer solved my case problem.

Friday, 24 July 2015

Razor syntax is loop odd or even

I had to render a table of data today, and alternate classes on the rows. Here's the Razor:
tr class="@(rowCounter%2 == 0 ? "even" : "odd")"

Wednesday, 24 June 2015

Prevent browser from loading drag and dropped file

I've been implementing a drag-and-drop uploader today but found that if the user missed the drop area the browser would load the file directly. Annoying huh? I overcame this with this nifty bit of javascript:
window.addEventListener("dragover",function(e){
  e = e || event;
  e.preventDefault();
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
},false);

Tuesday, 9 June 2015

Untappable areas with Android 4.x and Phonegap

I came across a problem today while using jQuery to hide one div and show another in its place. The touchable elements on the revealed (buttons, input fields) weren't responding to touch. I found on SO that adding the following style to the problem div fixes the problem:
.androidpaintfix {
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0, 0, 0);
}
If you're doing this to a div that needs to be hidden then you need to do it dynamically in JS like so:
$("#formLogin").addClass('androidpaintfix');

Friday, 29 May 2015

Throw an exception in Obj C

I've just been implementing HockeyApp and GetSentry crash reporting in one of our iOS native apps, and this handy piece of code came in useful for testing what happens when an exception is thrown.


   
        NSException* myException = [NSException
                                    exceptionWithName:@"TestExcpetion"
                                    reason:@"Just testing"
                                    userInfo:nil];
        @throw myException;

Friday, 20 March 2015

Using Swift code in Objective-C

I had a right pain getting this to work, once again Apple seem to have created something bafflingly unintuitive. I found these instructions elsewhere and have copied them virtually unmodified:

The file name of the generated header is "ModuleName-Swift.h". The ModuleName here is the Product Module Name, here's how to get to it:

1. Select your project in Project Navigator, then select project name under the word Project, so it’ll show you your project settings.

2. Select Build Settings tab on top, and find the Packaging section (you can type its name in the search bar). Here’s Product Module Name. If its value is the name of your project, then let it be, but you may want to change it if the value is a little bit different from the name of the project. I’d recommend not to use spaces or any other non-alphanumeric characters, here’s why:
If it has spaces or any other non-alphanumeric characters, they’ll become replaced with underscores (_) in the header file name. Also, Apple tells us that “if the name begins with a number, the first number is replaced with an underscore”.

Now build the project. Make sure that you have no build errors at all — Xcode must say “Build succeeded”. If it happened, then Xcode have probably generated the header. It won't appear in your project in Xcode or in its folder. It’s generated into a temporary build directory. Try to import it into the file where you want to use your Swift code by typing

#import "ModuleName-Swift.h"

In which ModuleName is your Product Module Name. You have to type it blindly, there’s no autocompletion here. So type this and build your project again. If you got “Build succeeded” message, then you’re done and Swift code is successfully integrated into Objective-C. It even autocompletes your class names, methods and variables written in Swift.

Tuesday, 17 March 2015

Android action actionDone button not appearing on soft keyboard

So, I have an EditText field, and I wanted the user to be able to dismiss the keyboard with a 'Done' button on the keyboard. So I added the following to my EditText element in the layout xml:
android:imeOptions="actionDone"
But this didn't work. No button on keyboard! Eventually I got it working by adding the following as well:
android:singleLine="true"

Monday, 16 March 2015

Xamarin - async post to REST service

Today I had to make a Xamarin Android app post a user's email address to a server. I created a new REST service using MVC Web API, with a simple single-table code-first Entity Framework database behind it.

At the app end, I assigned an async click event to the submit button like below. This is non-critical functionality and the response from the server was irrelevant here so I didn't need to do anything with it, and nor did I have to re-attempt at a later time in the case of no network availability:
            //OnCreate

            var btnContinue = FindViewById<imagebutton>(Resource.Id.btnContinue);
            _txtEmail = FindViewById<edittext>(Resource.Id.txtEmail);

            btnContinue.Click += async (sender, e) =>
            {
                //TODO validate email input and check not null

                //send email to email REST api
                JsonValue json = await PostEmailAsync("http://myrestservice.net/api/User/", _txtEmail.Text);

                //could do something with response here if necessary

                // Send the user to next screen, or do anything with the UI you need to.
            };


             //PostEmailSync

         private async Task<jsonvalue> PostEmailAsync(string url,string email)
        {  

            var cm = (ConnectivityManager)AppContext.GetSystemService(ConnectivityService);
            var activeNetwork = cm.ActiveNetworkInfo;
            var isConnected = activeNetwork != null && activeNetwork.IsConnected;

            if (isConnected)
            { 
                // Create an HTTP web request using the URL:
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
                request.ContentType = "application/json";
                request.Method = "POST";

                using (var streamWriter = new StreamWriter(request.GetRequestStream()))
                {
                    string json = "{Email:'" + email + "'}";

                    streamWriter.Write(json);
                    streamWriter.Flush();
                    streamWriter.Close();
                }


                // Send the request to the server and wait for the response:
                using (WebResponse response = await request.GetResponseAsync())
                {
                    // Get a stream representation of the HTTP web response:
                    using (Stream stream = response.GetResponseStream())
                    {
                        // Use this stream to build a JSON document object:
                        JsonValue jsonDoc = await Task.Run(() => JsonObject.Load(stream));
                        Console.Out.WriteLine("Response: {0}", jsonDoc.ToString());

                        // Return the JSON document:
                        return jsonDoc;
                    }
                }
           }
   
            return null;
        }

Friday, 6 February 2015

Using C# dynamic type and NewtonSoft.Json to deserialize JSON

Today I had a requirement to poke a JSON api and capture the response as part of a payment gateway, all from my C# code-behind in a .Net webforms project. Dynamic seemed a good way to go:
                var results = JsonConvert.DeserializeObject(jsonResponseFromApi);
                var oneThingIWant = results.thingYouWant;
                var anotherThingIWant = results.something.somethingDeeper;

Tuesday, 27 January 2015

Deleting svn files and directories, Mac OSX

I recently inherited a project that used to be in svn and is now thankfully in git. Unfortunately all the old svn files were still hanging around. To remove them I did this from the root of the project
find . -name .svn  -type d -print0 |xargs -0 rm -rf

Wednesday, 7 January 2015

Entity Framework - Unable to update EntitySet - it has a DefiningQuery and no element exists to support the current operation.

I had this error when working on an older .Net site yesterday with EF4. It seems that the db table wasn't setup with a primary key which apparently makes EF see it as a view. Looking at the XML in the .edmx file revealed this for my table:

<entityset Name="SpecialFeatures" EntityType="EB.Store.SpecialFeatures" store:Type="Tables" store:Schema="dbo" store:Name="SpecialFeatures">
            <definingquery>SELECT 
      [SpecialFeatures].[Id] AS [Id], 
      [SpecialFeatures].[ProductDetailIcon] AS [ProductDetailIcon], 
      [SpecialFeatures].[SearchResultsIcon] AS [SearchResultsIcon], 
      [SpecialFeatures].[Name] AS [Name]
      FROM [dbo].[SpecialFeatures] AS [SpecialFeatures]
</definingquery>
          </entityset>
To overcome this problem I performed the following surgery on the db and xml:
  1. Add a primary key to the db table in SSMS
  2. Open edmx file in text editor
  3. Locate the entity in the edmx:StorageModels element
  4. Remove the DefiningQuery entirely
  5. Rename the store:Schema="dbo" to Schema="dbo"
  6. Remove the store:Name property