Commit 62240e5b authored by Jason Williams's avatar Jason Williams
Browse files

Update mock generator and xbox test app.

Updates the mock generator class to be more robust and allow other methods than get and websocket.

Updates the xbox test app to be the XboxWDPDriver.exe, which can store and retrieve credentials and default console, allowing this to feel like a true command line tool. Updates the XbUser.cmd script to show the functionality a bit. If both creds and console are stored now you can run "XbUser.cmd list" and it will print output very similar to "XbUser.exe list" :)

Also adds a /op:connect operation to the test app which will save the console as the default (and persist the WDP creds).
parent efbc8675
Loading
Loading
Loading
Loading
+0 −176
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="DevicePortalConnection.cs" company="Microsoft Corporation">
//     Licensed under the MIT License. See LICENSE.TXT in the project root license information.
// </copyright>
//----------------------------------------------------------------------------------------------

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using Microsoft.Tools.WindowsDevicePortal;
using static Microsoft.Tools.WindowsDevicePortal.DevicePortal;

namespace MockDataGenerator
{
    /// <summary>
    /// IDevicePortalConnection implementation for MockDataGenerator test project
    /// </summary>
    public class DevicePortalConnection : IDevicePortalConnection
    {
        /// <summary>
        /// Device Certificate
        /// </summary>
        private X509Certificate2 deviceCertificate = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="DevicePortalConnection"/> class.
        /// </summary>
        /// <param name="address">device identifier</param>
        /// <param name="userName">WDP username</param>
        /// <param name="password">WDP password</param>
        public DevicePortalConnection(
            string address,
            string userName,
            string password)
        {
            this.Connection = new Uri(string.Format("https://{0}", address));
            this.Credentials = new NetworkCredential(userName, password);
        }

        /// <summary>
        /// Gets Connection property
        /// </summary>
        public Uri Connection
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets Web Socket Connection property
        /// </summary>
        public Uri WebSocketConnection
        {
            get
            {
                if (this.Connection == null)
                {
                    return null;
                }

                string absoluteUri = this.Connection.AbsoluteUri;

                if (absoluteUri.StartsWith("https", StringComparison.InvariantCultureIgnoreCase))
                {
                    return new Uri(Regex.Replace(absoluteUri, "https", "wss", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));
                }
                else
                {
                    return new Uri(Regex.Replace(absoluteUri, "http", "ws", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));
                }
            }
        }

        /// <summary>
        /// Gets Credentials property
        /// </summary>
        public NetworkCredential Credentials
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets or sets device family
        /// </summary>
        public string Family
        { 
            get; 
            set;
        }

        /// <summary>
        /// Gets or sets the device name
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets device OS Info
        /// </summary>
        public OperatingSystemInformation OsInfo
        {
            get;
            set;
        }

        /// <summary>
        /// Returns certificate data
        /// </summary>
        /// <returns>certificate data</returns>
        public byte[] GetDeviceCertificateData()
        {
            return this.deviceCertificate.GetRawCertData();
        }

        /// <summary>
        /// Validates and sets the device certificate.
        /// </summary>
        /// <param name="certificate">The device's root certificate.</param>
        public void SetDeviceCertificate(X509Certificate2 certificate)
        {
            if (!certificate.IssuerName.Name.Contains(DevicePortalCertificateIssuer))
            {
                throw new DevicePortalException(
                    (HttpStatusCode)0,
                    "Invalid certificate issuer",
                    null,
                    "Failed to download device certificate");
            }

            this.deviceCertificate = certificate;
        }

        /// <summary>
        /// Sets certificate data
        /// </summary>
        /// <param name="certificateData">certificate data</param>
        public void SetDeviceCertificate(byte[] certificateData)
        {
            X509Certificate2 cert = new X509Certificate2(certificateData);
            if (!cert.IssuerName.Name.Contains(DevicePortalCertificateIssuer))
            {
                throw new DevicePortalException(
                    (HttpStatusCode)0,
                    "Invalid certificate issuer",
                    null,
                    "Failed to download device certificate");
            }

            this.deviceCertificate = cert;
        }

        /// <summary>
        /// MockDataGenerator will never update the connection.
        /// </summary>
        /// <param name="requiresHttps">https required</param>
        public void UpdateConnection(bool requiresHttps)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///  MockDataGenerator will never update the connection.
        /// </summary>
        /// <param name="ipConfig">IP info</param>
        /// <param name="requiresHttps">https required</param>
        public void UpdateConnection(IpConfiguration ipConfig, bool requiresHttps)
        {
            throw new NotImplementedException();
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="DevicePortalConnection.cs" />
    <Compile Include="ParameterHelper.cs" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ namespace MockDataGenerator
        /// <summary>
        /// Device Identifier identifier string
        /// </summary>
        public static readonly string IpOrHostname = "ip";
        public static readonly string FullAddress = "address";

        /// <summary>
        /// WDP Username identifier string
+60 −28
Original line number Diff line number Diff line
@@ -26,22 +26,23 @@ namespace MockDataGenerator
        /// <summary>
        /// Usage string
        /// </summary>
        private const string GeneralUsageMessage = "Usage: /ip:<system-ip or hostname> /user:<WDP username> /pwd:<WDP password> [/endpoint:<api to call>] [/directory:<directory to save mock data file(s)>";
        private const string GeneralUsageMessage = "Usage: /address:<URL for device (eg. https://10.0.0.1:11443)> /user:<WDP username> /pwd:<WDP password> [/endpoint:<api to call>] [/directory:<directory to save mock data file(s)>";

        /// <summary>
        /// Endpoints for REST calls to populate
        /// Endpoints for REST calls to populate. Feel free to override this list (especially locally) to
        /// facilitate generating a large number of mock files all simultaneously.
        /// </summary>
        private static readonly string[] Endpoints = 
        {
            DevicePortal.DeviceFamilyApi,
            DevicePortal.MachineNameApi,
            DevicePortal.OsInfoApi,
            DevicePortal.XboxLiveUserApi,
            DevicePortal.XboxSettingsApi,
            DevicePortal.SystemPerfApi,
            DevicePortal.RunningProcessApi,
            WebSocketOpertionPrefix + DevicePortal.SystemPerfApi,
            WebSocketOpertionPrefix + DevicePortal.RunningProcessApi
        private static readonly Endpoint[] Endpoints = 
        {
            new Endpoint(HttpMethods.Get, DevicePortal.DeviceFamilyApi),
            new Endpoint(HttpMethods.Get, DevicePortal.MachineNameApi),
            new Endpoint(HttpMethods.Get, DevicePortal.OsInfoApi),
            new Endpoint(HttpMethods.Get, DevicePortal.XboxLiveUserApi),
            new Endpoint(HttpMethods.Get, DevicePortal.XboxSettingsApi),
            new Endpoint(HttpMethods.Get, DevicePortal.SystemPerfApi),
            new Endpoint(HttpMethods.Get, DevicePortal.RunningProcessApi),
            new Endpoint(HttpMethods.WebSocket, DevicePortal.SystemPerfApi),
            new Endpoint(HttpMethods.WebSocket, DevicePortal.RunningProcessApi),
        };

        /// <summary>
@@ -71,15 +72,15 @@ namespace MockDataGenerator
                return;
            }

            if (!parameters.HasParameter(ParameterHelper.IpOrHostname) || !parameters.HasParameter(ParameterHelper.WdpUser) || !parameters.HasParameter(ParameterHelper.WdpPassword))
            if (!parameters.HasParameter(ParameterHelper.FullAddress) || !parameters.HasParameter(ParameterHelper.WdpUser) || !parameters.HasParameter(ParameterHelper.WdpPassword))
            {
                Console.WriteLine("Missing one or more required parameter(s). Must provide ip, user, and pwd");
                Console.WriteLine("Missing one or more required parameter(s). Must provide address, user, and pwd");
                Console.WriteLine();
                Console.WriteLine(GeneralUsageMessage);
                return;
            }

            DevicePortalConnection connection = new DevicePortalConnection(parameters.GetParameterValue(ParameterHelper.IpOrHostname), parameters.GetParameterValue(ParameterHelper.WdpUser), parameters.GetParameterValue(ParameterHelper.WdpPassword));
            IDevicePortalConnection connection = new DefaultDevicePortalConnection(parameters.GetParameterValue(ParameterHelper.FullAddress), parameters.GetParameterValue(ParameterHelper.WdpUser), parameters.GetParameterValue(ParameterHelper.WdpPassword));
            DevicePortal portal = new DevicePortal(connection);

            Task connectTask = portal.Connect(updateConnection: false);
@@ -111,32 +112,27 @@ namespace MockDataGenerator
                Directory.CreateDirectory(directory);
            }


            if (parameters.HasParameter("endpoint"))
            {
                HttpMethods httpMethod = HttpMethods.Get;
                string endpoint = parameters.GetParameterValue("endpoint");

                if (endpoint.StartsWith(WebSocketOpertionPrefix, StringComparison.OrdinalIgnoreCase))
                if (parameters.HasParameter("method"))
                {
                    httpMethod = HttpMethods.WebSocket;
                    endpoint = endpoint.Substring(WebSocketOpertionPrefix.Length);
                    httpMethod = (HttpMethods)Enum.Parse(typeof(HttpMethods), parameters.GetParameterValue("method"));
                }

                string endpoint = parameters.GetParameterValue("endpoint");

                Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod);
                saveResponseTask.Wait();
            }
            else
            {
                foreach (string endpoint in Endpoints)
                {
                    string finalEndpoint = endpoint;
                    HttpMethods httpMethod = HttpMethods.Get;

                    if (endpoint.StartsWith(WebSocketOpertionPrefix, StringComparison.OrdinalIgnoreCase))
                foreach (Endpoint endpoint in Endpoints)
                {
                        httpMethod = HttpMethods.WebSocket;
                        finalEndpoint = endpoint.Substring(WebSocketOpertionPrefix.Length);
                    }
                    HttpMethods httpMethod = endpoint.Method;
                    string finalEndpoint = endpoint.Value;

                    try
                    {
@@ -159,5 +155,41 @@ namespace MockDataGenerator

            Console.WriteLine("Data generated in directory {0}. Please make sure to remove any personally identifiable information from the response(s) before adding them as mock responses.", directory);
        }

        /// <summary>
        /// Encapsulation of an endpoint and its HTTP method.
        /// </summary>
        private class Endpoint
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="Endpoint"/> class.
            /// </summary>
            /// <param name="method">The HTTP method this endpoint should use.</param>
            /// <param name="endpoint">The actual endpoint.</param>
            public Endpoint(HttpMethods method, string endpoint)
            {
                this.Method = method;
                this.Value = endpoint;
            }

            /// <summary>
            /// Gets or sets the HTTP Method.
            /// </summary>
            public HttpMethods Method { get; set; }

            /// <summary>
            /// Gets or sets the endpoint value.
            /// </summary>
            public string Value { get; set; }

            /// <summary>
            /// Overridden ToString method.
            /// </summary>
            /// <returns>Human readable representation of an Endpoint.</returns>
            public override string ToString()
            {
                return this.Method.ToString() + " : " + this.Value;
            }
        }
    }
}
+50 −3
Original line number Diff line number Diff line
@@ -5,10 +5,12 @@
//----------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using Microsoft.Tools.WindowsDevicePortal;
using Windows.Security.Credentials;
using static Microsoft.Tools.WindowsDevicePortal.DevicePortal;

namespace XboxWdpDriver
@@ -26,9 +28,9 @@ namespace XboxWdpDriver
        /// <summary>
        /// Initializes a new instance of the <see cref="DevicePortalConnection"/> class.
        /// </summary>
        /// <param name="address">device identifier</param>
        /// <param name="userName">WDP username</param>
        /// <param name="password">WDP password</param>
        /// <param name="address">The ip address or hostname of the device we are connecting to.</param>
        /// <param name="userName">The WDP username.</param>
        /// <param name="password">The WDP password.</param>
        public DevicePortalConnection(
            string address,
            string userName,
@@ -36,6 +38,51 @@ namespace XboxWdpDriver
        {
            this.Connection = new Uri(string.Format("https://{0}:11443", address));
            this.Credentials = new NetworkCredential(userName, password);

            PasswordVault vault = new PasswordVault();

            try
            {
                // Remove any existing stored creds for this address and add these ones.
                foreach (var cred in vault.FindAllByResource(address))
                {
                    vault.Remove(cred);
                }
            }
            catch (Exception)
            {
                // Do nothing. This is expected if no credentials have been previously stored
            }

            vault.Add(new PasswordCredential(address, userName, password));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DevicePortalConnection"/> class.
        /// This version of the contructor can be used if WDP credentials are not provided,
        /// and should be used if they were previously persisted or are not needed.
        /// </summary>
        /// <param name="address">The ip address or hostname of the device we are connecting to.</param>
        public DevicePortalConnection(
            string address)
        {
            this.Connection = new Uri(string.Format("https://{0}:11443", address));

            try
            {
                PasswordVault vault = new PasswordVault();
                // Set the first stored cred as our network creds.
                IReadOnlyList<PasswordCredential> creds = vault.FindAllByResource(address);
                if (creds != null && creds.Count > 0)
                {
                    creds[0].RetrievePassword();
                    this.Credentials = new NetworkCredential(creds[0].UserName, creds[0].Password);
                }
            }
            catch (Exception)
            {
                // Do nothing. No credentials were stored. If they are needed, REST calls will fail with Unauthorized.
            }
        }

        /// <summary>
Loading