ページ

Showing posts with label Out of Browser. Show all posts
Showing posts with label Out of Browser. Show all posts

Saturday, August 20, 2011

facebook and twitter application implemented in silverlight.

It's easy to create facebook and twitter application implemented in silverlight, but as for twitter, it doesn't work because of Cross-Domain matter.
So as one of the solutions, It should be implemented with 'Out of browser' & 'Elevated Trusted mode'.
Then, it will be a kind of desktop application.( I actually left 'Callback URL' blank. )

However, there's an important reminder about it.

How we can implant 'consumer_secret' into the application.
or
How we can let the application get/download 'consumer_secret' from somewhere else.

Well, I don't know the best practice, but I did encrypt the key as a countermeasure.
* Maybe, It's better to use web pages like asp.net before getting oauth_token and oauth_token_secret.

Anyway, I tried to create the applications because I wanted to know how 'OAuth 1.0a' and 'OAuth 2.0' work.

Silverlight client for facebook.
https://social-media-applications.appspot.com/facebook/silverlight/index.html

Silverlight client for twitter ( Out Of Browser ).
https://social-media-applications.appspot.com/twitter/silverlight/index.html


Get uri, query and headers

private void OAuth(string url, string httpMethod, Dictionary<string, string> parameters, out Uri uri, out string query, out Dictionary<HttpRequestHeader, string> headers)
{
    query = string.Empty;
    uri = null;
    headers = new Dictionary<HttpRequestHeader, string>();
    parameters["oauth_signature"] = string.Empty;
    var param = parameters.OrderBy(x => x.Key);

    StringBuilder sb = new StringBuilder();
    foreach (var p in param)
    {
        if (!string.IsNullOrEmpty(p.Value))
            sb.Append(@"&" + p.Key + "=" + UrlEncode(p.Value));
    }
            sb.Remove(0, 1);
    string signatureBase = string.Format(@"{0}&{1}&{2}", httpMethod.ToUpper(), UrlEncode(url), UrlEncode(sb.ToString()));

    HMACSHA1 hmacsha1 = new HMACSHA1();
    hmacsha1.Key = Encoding.UTF8.GetBytes(string.Format("{0}&{1}", UrlEncode(parameters["consumer_secret"]), UrlEncode(parameters["oauth_token_secret"])));
    byte[] dataBuffer = Encoding.UTF8.GetBytes(signatureBase);
    byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);

    string sig = Convert.ToBase64String(hashBytes);
    sb.Append(@"&oauth_signature=" + UrlEncode(sig));
    parameters["oauth_signature"] = sig;

    query = sb.ToString();
    string getURL = url;
    if (httpMethod.ToUpper().Equals("GET"))
    {
        if (!string.IsNullOrEmpty(query))
            getURL += '?' + query;
    }
    uri = new Uri(getURL, UriKind.RelativeOrAbsolute);
    if (httpMethod.ToUpper().Equals("POST"))
    {
        headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
        headers[HttpRequestHeader.Authorization] = GetHeader(uri, parameters);
    }
}


URL Encode

public string UrlEncode(string value)
{
    string urlChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
    StringBuilder result = new StringBuilder();
    byte[] data = Encoding.UTF8.GetBytes(value);
    for (int i = 0; i < data.Length; i++)
    {
        int c = data[i];
        if (c < 0x80 && urlChars.Contains((char)c))
            result.Append((char)c);
        else
            result.Append('%' + String.Format("{0:X2}", (int)data[i]));
    }
    return result.ToString();
}

Nonce

private string GetNonce()
{
    string nonceChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    StringBuilder result = new StringBuilder(8);
    Random random = new Random();
    for (int i = 0; i < 8; ++i)
        result.Append(nonceChars[random.Next(nonceChars.Length)]);
    return result.ToString();
}

Timestamp

private string GetTimestamp()
{
    TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
    return Convert.ToInt64(ts.TotalSeconds).ToString();
}

Authorization Header

private string GetHeader(Uri uri, Dictionary<string, string> parameters)
{
    StringBuilder realm = new StringBuilder();
    realm.Append(uri.Scheme);
    realm.Append("://");
    realm.Append(uri.Host);
    if (uri.Port != 80 && uri.Port != 443)
        realm.Append(':' + uri.Port);

    StringBuilder header = new StringBuilder();
    header.Append("Authorization: ");
    header.Append("OAuth realm=\"" + realm.ToString() + "\"");
    foreach (var p in parameters)
    {
            header.Append(", " + p.Key + "=\"" + UrlEncode(p.Value) + "\"");
    }
    header.Append("\r\n");
    return header.ToString();
}


Usage : Post message on your twitter

public void Tweet(string message)
{
    Dictionary<string, string> param = new Dictionary<string, string>();
    param["oauth_consumer_key"] = "xxxxxxxxxxx";
    // .... setting required parameters
    param["oauth_version"] = "1.0";
    param["status"] = message;

    Uri uri;
    string query;
    Dictionary<HttpRequestHeader, string> headers;
    OAuth("https://api.twitter.com/statuses/update.json", "POST", param, out uri, out query, out headers);
    
    WebClient wc = new WebClient();
    foreach (var header in headers)
        wc.Headers[header.Key] = header.Value;
    wc.UploadStringCompleted += OnUploadStringCompleted;
    wc.UploadStringAsync(uri, query);
}

void OnUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
    // Get Json formatted data by e.Result if e.Error equals NULL.
}




OAuth 1.0a is really harder to be implemented than OAuth 2.0, but this taught me a good lesson.

Wednesday, February 2, 2011

Silverlight RSS Reader ( Out Of Browser Version )

I posted Silverlight RSS Reader before, but that requires the proxy server to get RSS feeds.
( See Simple Silverlight RSS Reader. (MVVM Pattern) )
So I was wondering if I create the application with OOB(out of browser).

* Out-of-Browser Settings on Visual Studio
Check "Require elevated trust when running outside the browser".


* Install PFX file on the silverlight project.

1-1.Create a self-signed SSL certificate ( use for text, i.e. non trusted )

makecert.exe( Visual studio pro or windows sdk. )
http://msdn.microsoft.com/en-US/library/bfsktky3(v=VS.100).aspx


(1) Create a root certificate authority.
makecert -n "CN=Dummy Certificate Authority" -r -a sha1 -sr LocalMachine -sky signature -sv OOBRootCA.pvk OOBRootCA.cer

(2) Create a code-signing certificate.
makecert -sv OOBCodeSigningCA.pvk -iv OOBRootCA.pvk -n "CN=OOB Code Signing CA" -ic OOBRootCA.cer OOBCodeSigningCA.cer

(3) Convert the certificate and key to pfx file.
pvk2pfx -pvk OOBCodeSigningCA.pvk -spc OOBCodeSigningCA.cer -pfx DummyOOBCodeSigningCA.pfx -po <password>


1-2. Install the file on the project.

(1) In solution explorer, right-click the project name, and then click Properties. In the Properties Pages dialog box, click the Signing tab.
























(2) Click "Select from File" button and Select the pfx file.






















(3) Enter the password.














(4) Save Properties, then it's done.






* Coding Consideration on OOB

1. Check network status and Download itself if updated.

App.xaml.cs
public App()
{
   .
   .
   .
 NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;


        if (this.IsRunningOutOfBrowser)
            this.CheckAndDownloadUpdateCompleted += App_CheckAndDownloadUpdateCompleted;
   .
   .
   .

}

private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
    if (NetworkInterface.GetIsNetworkAvailable())
    {
        // something
    }
    else
    {
        // something
    }
}

private void App_CheckAndDownloadUpdateCompleted(
                     object sender,
                     CheckAndDownloadUpdateCompletedEventArgs e)
{
    if (e.UpdateAvailable)
    {
        MessageBox.Show("The update has been downloaded. Please restart the application.", 
                        "Application Update",MessageBoxButton.OK);
    }
}



2. Custom Windows Control bar for Silverlight OOB.

WindowControlBar.xaml
<UserControl x:Class="RSSReaderOOB.WindowControlBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="26" d:DesignWidth="300">

    <Grid Background="LightGray" Height="26" MaxHeight="26" MinHeight="26">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        <Image x:Name="IconImage" Source="/Images/IconSL16.png" Width="16" Height="16" Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="3,0,0,0" />
        <TextBlock x:Name="TitleTextBlock" Margin="22,0,0,0" FontSize="13" Text="Silverlight OOB Application" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" />
        <StackPanel x:Name="WindowControlBarRoot" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Top"
                        Margin="0,0,0,0" HorizontalAlignment="Right">
            <Canvas Width="30" x:Name="wcbMinimizeButton" Cursor="Hand" Background="#00000000"
                        Visibility="Visible" Height="20" ToolTipService.ToolTip="Minimize">
                <Border Width="30" Height="20" Background="#FF939393" BorderBrush="#FF000000"
                            BorderThickness="1,1,0,1" CornerRadius="0,0,0,5">
                    <Border BorderThickness="1.5,1.5,1.5,1.5" CornerRadius="0,0,0,5">
                        <Border.Background>
                            <LinearGradientBrush EndPoint="0.514,0.623"
                                                     StartPoint="0.514,0.191">
                                <GradientStop Color="#FF828282" Offset="0"/>
                                <GradientStop Color="#FF262626" Offset="1"/>
                            </LinearGradientBrush>
                        </Border.Background>
                        <Rectangle Margin="6,9,6,3" Fill="#FFD6D5D5" Stroke="#FF000000"
                                       StrokeThickness="0.5"/>
                    </Border>
                </Border>
            </Canvas>
            <Canvas Width="30" x:Name="wcbMaximizeButton" Cursor="Hand" Background="#00000000"
                        Visibility="Visible" Height="20" ToolTipService.ToolTip="Maximize">
                <Border Width="30" Height="20" Background="#FF939393" BorderBrush="#FF000000"
                            BorderThickness="1,1,0,1">
                    <Border BorderThickness="1.5,1.5,1.5,1.5" CornerRadius="0,0,0,0" Width="29"
                                Height="18">
                        <Border.Background>
                            <LinearGradientBrush EndPoint="0.514,0.623"
                                                     StartPoint="0.514,0.191">
                                <GradientStop Color="#FF828282" Offset="0"/>
                                <GradientStop Color="#FF262626" Offset="1"/>
                            </LinearGradientBrush>
                        </Border.Background>
                        <Border Background="#FFD6D5D5" Margin="6,2,6,2" BorderBrush="#FF000000"
                                    BorderThickness="0.5,0.5,0.5,0.5">
                            <Rectangle Stroke="#FF000000" Margin="2,2,2,2"
                                           StrokeThickness="0.5">
                                <Rectangle.Fill>
                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                        <GradientStop Color="#FF828282" Offset="0"/>
                                        <GradientStop Color="#FF262626" Offset="1"/>
                                    </LinearGradientBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                        </Border>
                    </Border>
                </Border>
            </Canvas>
            <Canvas Width="40" x:Name="wcbCloseButton" Cursor="Hand" Background="#00000000"
                        Opacity="1" Height="20" ToolTipService.ToolTip="Close">
                <Border Width="40" Height="20" Background="#FF939393" BorderBrush="#FF000000"
                            BorderThickness="1,1,1,1" CornerRadius="0,0,5,0">
                    <Border BorderThickness="1,1,1,1" CornerRadius="0,0,5,0" Width="37"
                                Height="16" x:Name="border">
                        <Border.Background>
                            <LinearGradientBrush EndPoint="0.514,0.623"
                                                     StartPoint="0.514,0.191">
                                <GradientStop Color="#FF956161" Offset="0"/>
                                <GradientStop Color="#FF490E0E" Offset="1"/>
                            </LinearGradientBrush>
                        </Border.Background>
                        <TextBlock Text="X" TextWrapping="Wrap" Foreground="#FFECECEC"
                                       HorizontalAlignment="Center" VerticalAlignment="Center"
                                       x:Name="textBlock"/>
                    </Border>
                </Border>
            </Canvas>
        </StackPanel>

    </Grid>
</UserControl>

WindowControlBar.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace RSSReaderOOB
{
    public partial class WindowControlBar : UserControl
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(WindowControlBar), new PropertyMetadata(OnTitleChanged));
        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(Uri), typeof(WindowControlBar), new PropertyMetadata(OnIconChanged));

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public Uri Icon
        {
            get { return (Uri)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        private static void OnTitleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                string newTitle = e.NewValue as string;
                WindowControlBar wcb = sender as WindowControlBar;
                wcb.TitleTextBlock.Text = newTitle;
            }
        }

        private static void OnIconChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                if (e.NewValue is Uri)
                {
                    WindowControlBar wcb = sender as WindowControlBar;
                    wcb.IconImage.Source = new System.Windows.Media.Imaging.BitmapImage(e.NewValue as Uri);
                }
            }
        }

        public WindowControlBar()
        {
            InitializeComponent();
            if (Application.Current.IsRunningOutOfBrowser)
            {
                this.Visibility = Visibility.Visible;
                this.wcbMaximizeButton.MouseLeftButtonDown += new MouseButtonEventHandler(wcbMaximizeButton_MouseLeftButtonDown);
                this.wcbMinimizeButton.MouseLeftButtonDown += new MouseButtonEventHandler(wcbMinimizeButton_MouseLeftButtonDown);
                this.wcbCloseButton.MouseLeftButtonDown += new MouseButtonEventHandler(wcbCloseButton_MouseLeftButtonDown);
                this.MouseLeftButtonDown += new MouseButtonEventHandler(WindowControlBar_MouseLeftButtonDown);
            }
            else
                this.Visibility = Visibility.Collapsed;
        }

        void WindowControlBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Application.Current.MainWindow.DragMove();
        }

        void wcbCloseButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Application.Current.MainWindow.Close();
        }

        void wcbMinimizeButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Application.Current.MainWindow.WindowState = WindowState.Minimized;
        }

        void wcbMaximizeButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (Application.Current.MainWindow.WindowState == WindowState.Normal)
                Application.Current.MainWindow.WindowState = WindowState.Maximized;
            else
                Application.Current.MainWindow.WindowState = WindowState.Normal;
        }
    }
}


Here are the capture images of the application.

1.Start the application and then click Install button.
The Application on the browser.




















2.Click Install button.
* Security Warning appears because of Non-Trusted SSL.




















3.Enter a RSS feed url in the textbox.


















4. Done.




Thursday, December 17, 2009

Out of Browser

It's not easy to find out the best practice about "Out Of Browser", but as one of solutions on the Internet,
Online Catalog or something like that would be nice... I think.
Because the catalog always provides the latest information whenever we start the "Out of browser", differently from PDF or Word files.

Demo site ( Until Dec 31, 2009 )
http://lol.cloudapp.net/SilverlightCatalog.aspx


1. Silverlight Page







2. Installing Out of Browser



3. Starting Out of Browser







4. Starting Out of Browser when Network is not available



Adding "Out of Browser" on Silverlight is very easy, but not easy to add what kind of service on it ... as usual.