diff --git a/XboxWebApi/Authentication/AuthenticationService.cs b/XboxWebApi/Authentication/AuthenticationService.cs index 51129ac..cdd9de8 100644 --- a/XboxWebApi/Authentication/AuthenticationService.cs +++ b/XboxWebApi/Authentication/AuthenticationService.cs @@ -7,165 +7,198 @@ using XboxWebApi.Extensions; using XboxWebApi.Authentication.Model; using System.Text; +using System.Threading.Tasks; namespace XboxWebApi.Authentication { - public class AuthenticationService - { - public AccessToken AccessToken { get; set; } - public RefreshToken RefreshToken { get; set; } - public UserToken UserToken { get; set; } - public DeviceToken DeviceToken { get; set; } - public TitleToken TitleToken { get; set; } - public XToken XToken { get; set; } - public XboxUserInformation UserInformation { get; set; } - - public AuthenticationService() - { - } - - public AuthenticationService(WindowsLiveResponse wlResponse) - { - AccessToken = new AccessToken(wlResponse); - RefreshToken = new RefreshToken(wlResponse); - } - - public AuthenticationService(AccessToken accessToken, RefreshToken refreshToken) - { - AccessToken = accessToken; - RefreshToken = refreshToken; - } - - public static RestClientEx ClientFactory(string baseUrl, - JsonNamingStrategy naming = JsonNamingStrategy.Default) - { - return new RestClientEx(baseUrl, naming); - } - - public bool Authenticate() - { - WindowsLiveResponse windowsLiveTokens = RefreshLiveToken(RefreshToken); + public class AuthenticationService + { + public AccessToken AccessToken { get; set; } + public RefreshToken RefreshToken { get; set; } + public UserToken UserToken { get; set; } + public DeviceToken DeviceToken { get; set; } + public TitleToken TitleToken { get; set; } + public XToken XToken { get; set; } + public XboxUserInformation UserInformation { get; set; } + + public AuthenticationService() + { + } + + public AuthenticationService(WindowsLiveResponse wlResponse) + { + AccessToken = new AccessToken(wlResponse); + RefreshToken = new RefreshToken(wlResponse); + } + + public AuthenticationService(AccessToken accessToken, RefreshToken refreshToken) + { + AccessToken = accessToken; + RefreshToken = refreshToken; + } + + public static RestClientEx ClientFactory(string baseUrl, + JsonNamingStrategy naming = JsonNamingStrategy.Default) + { + return new RestClientEx(baseUrl, naming); + } + + public bool Authenticate() + { + return AuthenticateAsync().GetAwaiter().GetResult(); + } + + public async Task AuthenticateAsync() + { + WindowsLiveResponse windowsLiveTokens = await RefreshLiveTokenAsync(RefreshToken); AccessToken = new AccessToken(windowsLiveTokens); RefreshToken = new RefreshToken(windowsLiveTokens); - UserToken = AuthenticateXASU(AccessToken); - XToken = AuthenticateXSTS(UserToken, DeviceToken, TitleToken); - UserInformation = XToken.UserInformation; - return true; - } - - public static WindowsLiveResponse RefreshLiveToken( - RefreshToken refreshToken) - { - RestClientEx client = ClientFactory("https://login.live.com", - JsonNamingStrategy.SnakeCase); - RestRequestEx request = new RestRequestEx("oauth20_token.srf", Method.GET); - NameValueCollection nv = new Model.WindowsLiveRefreshQuery(refreshToken).GetQuery(); - request.AddQueryParameters(nv); - IRestResponse response = client.Execute(request); - return response.Data; - } - - public static UserToken AuthenticateXASU(AccessToken accessToken) - { - RestClientEx client = ClientFactory("https://user.auth.xboxlive.com"); - RestRequestEx request = new RestRequestEx("user/authenticate", Method.POST); - request.AddHeader("x-xbl-contract-version", "1"); - request.AddJsonBody(new XASURequest(accessToken)); - IRestResponse response = client.Execute(request); - return new UserToken(response.Data); - } - - public static DeviceToken AuthenticateXASD(AccessToken accessToken) - { - RestClientEx client = ClientFactory("https://device.auth.xboxlive.com"); - RestRequestEx request = new RestRequestEx("device/authenticate", Method.POST); + UserToken = await AuthenticateXASUAsync(AccessToken); + XToken = await AuthenticateXSTSAsync(UserToken, DeviceToken, TitleToken); + UserInformation = XToken.UserInformation; + return true; + } + + public static WindowsLiveResponse RefreshLiveToken(RefreshToken token) + { + return RefreshLiveTokenAsync(token).GetAwaiter().GetResult(); + } + + public static async Task RefreshLiveTokenAsync( + RefreshToken refreshToken) + { + RestClientEx client = ClientFactory("https://login.live.com", + JsonNamingStrategy.SnakeCase); + RestRequestEx request = new RestRequestEx("oauth20_token.srf", Method.GET); + NameValueCollection nv = new Model.WindowsLiveRefreshQuery(refreshToken).GetQuery(); + request.AddQueryParameters(nv); + IRestResponse response = await client.ExecuteTaskAsync(request); + return response.Data; + } + + public static UserToken AuthenticateXASU(AccessToken accessToken) + { + return AuthenticateXASUAsync(accessToken).GetAwaiter().GetResult(); + } + + public static async Task AuthenticateXASUAsync(AccessToken accessToken) + { + RestClientEx client = ClientFactory("https://user.auth.xboxlive.com"); + RestRequestEx request = new RestRequestEx("user/authenticate", Method.POST); + request.AddHeader("x-xbl-contract-version", "1"); + request.AddJsonBody(new XASURequest(accessToken)); + IRestResponse response = await client.ExecuteTaskAsync(request); + return new UserToken(response.Data); + } + + public DeviceToken AuthenticateXASD(AccessToken accessToken) + { + return AuthenticateXASDAsync(accessToken).GetAwaiter().GetResult(); + } + + public static async Task AuthenticateXASDAsync(AccessToken accessToken) + { + RestClientEx client = ClientFactory("https://device.auth.xboxlive.com"); + RestRequestEx request = new RestRequestEx("device/authenticate", Method.POST); request.AddHeader("x-xbl-contract-version", "1"); request.AddJsonBody(new XASDRequest(accessToken)); - IRestResponse response = client.Execute(request); + IRestResponse response = await client.ExecuteTaskAsync(request); return new DeviceToken(response.Data); - } - - public static TitleToken AuthenticateXAST(AccessToken accessToken, - DeviceToken deviceToken) - { - RestClientEx client = ClientFactory("https://title.auth.xboxlive.com"); + } + + public static TitleToken AuthenticateXAST(AccessToken accessToken, DeviceToken deviceToken) + { + return AuthenticateXASTAsync(accessToken, deviceToken).GetAwaiter().GetResult(); + } + + public static async Task AuthenticateXASTAsync(AccessToken accessToken, + DeviceToken deviceToken) + { + RestClientEx client = ClientFactory("https://title.auth.xboxlive.com"); RestRequestEx request = new RestRequestEx("title/authenticate", Method.POST); request.AddHeader("x-xbl-contract-version", "1"); - request.AddJsonBody(new XASTRequest(accessToken, deviceToken)); - IRestResponse response = client.Execute(request); + request.AddJsonBody(new XASTRequest(accessToken, deviceToken)); + IRestResponse response = await client.ExecuteTaskAsync(request); return new TitleToken(response.Data); - } - - public static XToken AuthenticateXSTS(UserToken userToken, - DeviceToken deviceToken=null, - TitleToken titleToken=null) - { - RestClientEx client = ClientFactory("https://xsts.auth.xboxlive.com"); - RestRequestEx request = new RestRequestEx("xsts/authorize", Method.POST); + } + + public static XToken AuthenticateXSTS(UserToken userToken, + DeviceToken deviceToken = null, + TitleToken titleToken = null) + { + return AuthenticateXSTSAsync(userToken, deviceToken, titleToken).GetAwaiter().GetResult(); + } + + public static async Task AuthenticateXSTSAsync(UserToken userToken, + DeviceToken deviceToken = null, + TitleToken titleToken = null) + { + RestClientEx client = ClientFactory("https://xsts.auth.xboxlive.com"); + RestRequestEx request = new RestRequestEx("xsts/authorize", Method.POST); request.AddHeader("x-xbl-contract-version", "1"); - request.AddJsonBody(new XSTSRequest(userToken, + request.AddJsonBody(new XSTSRequest(userToken, deviceToken: deviceToken, titleToken: titleToken)); - IRestResponse response = client.Execute(request); + IRestResponse response = await client.ExecuteTaskAsync(request); return new XToken(response.Data); - } - - public static string GetWindowsLiveAuthenticationUrl() - { - RestClientEx client = ClientFactory("https://login.live.com"); - RestRequestEx request = new RestRequestEx("oauth20_authorize.srf", Method.GET); - NameValueCollection nv = new Model.WindowsLiveAuthenticationQuery().GetQuery(); - request.AddQueryParameters(nv); - return client.BuildUri(request).ToString(); - } - - public static WindowsLiveResponse ParseWindowsLiveResponse(string url) - { - if (!url.StartsWith("https://login.live.com/oauth20_desktop.srf")) - { - throw new InvalidDataException(String.Format("Invalid URL to parse: {0}", url)); - } - - string urlFragment = new Uri(url).Fragment; - if (String.IsNullOrEmpty(urlFragment) || !urlFragment.StartsWith("#access_token")) - { - throw new InvalidDataException(String.Format("Invalid URL fragment: {0}", urlFragment)); - } - - // Cut off leading '#' - urlFragment = urlFragment.Substring(1); - - NameValueCollection queryParams = System.Web.HttpUtility.ParseQueryString( - urlFragment, System.Text.Encoding.UTF8); - - string[] expectedKeys = { - "expires_in", "access_token", "token_type", - "scope", "refresh_token", "user_id"}; - - foreach (string key in expectedKeys) - { - string val = queryParams[key]; - if (String.IsNullOrEmpty(val)) - throw new InvalidDataException( - String.Format("Key not found: {0} || Invalid value: {1}", key, val)); - } - - return new WindowsLiveResponse(queryParams); - } - - public static AuthenticationService LoadFromFile(FileStream fs) - { - byte[] buf = new byte[fs.Length]; - fs.Read(buf, 0, buf.Length); - string s = Encoding.UTF8.GetString(buf); - return JsonConvert.DeserializeObject(s); - } - - public void DumpToFile(FileStream fs) - { - string s = JsonConvert.SerializeObject(this, Formatting.Indented); - byte[] bytes = Encoding.UTF8.GetBytes(s); - fs.Write(bytes, 0, bytes.Length); - } + } + + public static string GetWindowsLiveAuthenticationUrl() + { + RestClientEx client = ClientFactory("https://login.live.com"); + RestRequestEx request = new RestRequestEx("oauth20_authorize.srf", Method.GET); + NameValueCollection nv = new Model.WindowsLiveAuthenticationQuery().GetQuery(); + request.AddQueryParameters(nv); + return client.BuildUri(request).ToString(); + } + + public static WindowsLiveResponse ParseWindowsLiveResponse(string url) + { + if (!url.StartsWith(WindowsLiveConstants.RedirectUrl)) + { + throw new InvalidDataException(String.Format("Invalid URL to parse: {0}", url)); + } + + string urlFragment = new Uri(url).Fragment; + if (String.IsNullOrEmpty(urlFragment) || !urlFragment.StartsWith("#access_token")) + { + throw new InvalidDataException(String.Format("Invalid URL fragment: {0}", urlFragment)); + } + + // Cut off leading '#' + urlFragment = urlFragment.Substring(1); + + NameValueCollection queryParams = System.Web.HttpUtility.ParseQueryString( + urlFragment, System.Text.Encoding.UTF8); + + string[] expectedKeys = { + "expires_in", "access_token", "token_type", + "scope", "refresh_token", "user_id"}; + + foreach (string key in expectedKeys) + { + string val = queryParams[key]; + if (String.IsNullOrEmpty(val)) + throw new InvalidDataException( + String.Format("Key not found: {0} || Invalid value: {1}", key, val)); + } + + return new WindowsLiveResponse(queryParams); + } + + public static AuthenticationService LoadFromFile(FileStream fs) + { + byte[] buf = new byte[fs.Length]; + fs.Read(buf, 0, buf.Length); + string s = Encoding.UTF8.GetString(buf); + return JsonConvert.DeserializeObject(s); + } + + public void DumpToFile(FileStream fs) + { + string s = JsonConvert.SerializeObject(this, Formatting.Indented); + byte[] bytes = Encoding.UTF8.GetBytes(s); + fs.Write(bytes, 0, bytes.Length); + } } } diff --git a/XboxWebApi/Authentication/Model/WindowsLiveAuthenticationQuery.cs b/XboxWebApi/Authentication/Model/WindowsLiveAuthenticationQuery.cs index eac5070..86e911a 100644 --- a/XboxWebApi/Authentication/Model/WindowsLiveAuthenticationQuery.cs +++ b/XboxWebApi/Authentication/Model/WindowsLiveAuthenticationQuery.cs @@ -1,41 +1,42 @@ using System; using System.Collections.Specialized; +using XboxWebApi.Authentication; namespace XboxWebApi.Authentication.Model { public class WindowsLiveAuthenticationQuery { - public string ResponseType { get; internal set; } - public string Scope { get; internal set; } - public string RedirectUri { get; internal set; } - public string ClientId { get; internal set; } - public string Display { get; internal set; } - public string Locale { get; internal set; } + public string ResponseType { get; internal set; } + public string Scope { get; internal set; } + public string RedirectUri { get; internal set; } + public string ClientId { get; internal set; } + public string Display { get; internal set; } + public string Locale { get; internal set; } public WindowsLiveAuthenticationQuery( - string responseType="token", - string scope="service::user.auth.xboxlive.com::MBI_SSL", - string redirectUri="https://login.live.com/oauth20_desktop.srf", - string clientId="0000000048093EE3", - string display="touch", string locale="en") + string responseType = "token", + string scope = WindowsLiveConstants.Scope, + string redirectUri = WindowsLiveConstants.RedirectUrl, + string clientId = WindowsLiveConstants.ClientId, + string display = "touch", string locale = "en") { - ResponseType = responseType; - Scope = scope; - RedirectUri = redirectUri; - ClientId = clientId; - Display = display; - Locale = locale; + ResponseType = responseType; + Scope = scope; + RedirectUri = redirectUri; + ClientId = clientId; + Display = display; + Locale = locale; } - public NameValueCollection GetQuery() + public NameValueCollection GetQuery() { - return new NameValueCollection{ - {"response_type", ResponseType}, + return new NameValueCollection{ + {"response_type", ResponseType}, {"scope", Scope}, - {"redirect_uri", RedirectUri}, + {"redirect_uri", RedirectUri}, {"client_id", ClientId}, - {"display", Display}, - {"locale", Locale} + {"display", Display}, + {"locale", Locale} }; } } diff --git a/XboxWebApi/Authentication/Model/WindowsLiveRefreshQuery.cs b/XboxWebApi/Authentication/Model/WindowsLiveRefreshQuery.cs index 2a7aecf..ea30a5a 100644 --- a/XboxWebApi/Authentication/Model/WindowsLiveRefreshQuery.cs +++ b/XboxWebApi/Authentication/Model/WindowsLiveRefreshQuery.cs @@ -1,35 +1,36 @@ using System; using System.Collections.Specialized; +using XboxWebApi.Authentication; namespace XboxWebApi.Authentication.Model { - public class WindowsLiveRefreshQuery + public class WindowsLiveRefreshQuery { - public string GrantType { get; internal set; } - public string ClientId { get; internal set; } - public string Scope { get; internal set; } - public string RefreshToken { get; internal set; } - - public WindowsLiveRefreshQuery( - RefreshToken refreshToken, - string grantType="refresh_token", - string clientId="0000000048093EE3", - string scope="service::user.auth.xboxlive.com::MBI_SSL") - { - GrantType = grantType; - ClientId = clientId; - Scope = scope; - RefreshToken = refreshToken.Jwt; - } + public string GrantType { get; internal set; } + public string ClientId { get; internal set; } + public string Scope { get; internal set; } + public string RefreshToken { get; internal set; } - public NameValueCollection GetQuery() - { - return new NameValueCollection{ - {"grant_type", GrantType}, - {"client_id", ClientId}, - {"scope", Scope}, - {"refresh_token", RefreshToken} - }; - } - } + public WindowsLiveRefreshQuery( + RefreshToken refreshToken, + string grantType = "refresh_token", + string clientId = WindowsLiveConstants.ClientId, + string scope = WindowsLiveConstants.Scope) + { + GrantType = grantType; + ClientId = clientId; + Scope = scope; + RefreshToken = refreshToken.Jwt; + } + + public NameValueCollection GetQuery() + { + return new NameValueCollection{ + {"grant_type", GrantType}, + {"client_id", ClientId}, + {"scope", Scope}, + {"refresh_token", RefreshToken} + }; + } + } } diff --git a/XboxWebApi/Authentication/WindowsLiveConstants.cs b/XboxWebApi/Authentication/WindowsLiveConstants.cs new file mode 100644 index 0000000..54f9edd --- /dev/null +++ b/XboxWebApi/Authentication/WindowsLiveConstants.cs @@ -0,0 +1,14 @@ +using System; + +namespace XboxWebApi.Authentication +{ + public static class WindowsLiveConstants + { + public const string ClientId = "0000000048093EE3"; + public const string Scope = "service::user.auth.xboxlive.com::MBI_SSL"; + public const string AuthorizeUrl = "https://login.live.com/oauth20_authorize.srf"; + public const string RefreshTokenUrl = "https://login.live.com/oauth20_token.srf"; + public const string RedirectUrl = "https://login.live.com/oauth20_desktop.srf"; + public const string ResponseType = "token"; + } +} \ No newline at end of file diff --git a/XboxWebApi/XboxWebApi.csproj b/XboxWebApi/XboxWebApi.csproj index f0ca4c6..9c3b51f 100644 --- a/XboxWebApi/XboxWebApi.csproj +++ b/XboxWebApi/XboxWebApi.csproj @@ -3,14 +3,14 @@ netstandard2.0;net452 OpenXbox.XboxWebApi - 0.2.4 + 0.2.5 Team OpenXbox Unoffical C# Xbox WebAPI, includes support for authentication with Windows Live / Xbox Live. false - Add AuthenticationService(WindowsLiveResponse) constructor + Add WindowsLiveConstants and add asyncness to authentication Copyright 2018 (c) Team OpenXbox xbox live api authentication - 0.2.4 + 0.2.5 https://github.com/OpenXbox/xbox-webapi-csharp https://github.com/OpenXbox/xbox-webapi-csharp/blob/master/LICENSE diff --git a/appveyor.yml b/appveyor.yml index 1809fef..17b0f28 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,18 +1,44 @@ version: 1.0.{build} -branches: - only: - - master + image: Visual Studio 2017 -nuget: - account_feed: true - project_feed: true + +configuration: + - Release + before_build: -- cmd: nuget restore + - cmd: dotnet restore + build: publish_nuget: true verbosity: minimal + +after_build: + - cmd: echo "Building publishable package for Windows x86" + - cmd: dotnet publish -c Release -r win-x86 -o win-x86 XboxWebApi.Cli + - cmd: 7z a XboxWebApiCli-%APPVEYOR_REPO_TAG_NAME%-windows-x86.zip %APPVEYOR_BUILD_FOLDER%\XboxWebApi.Cli\win-x86\* + - cmd: echo "Building publishable package for Windows x64" + - cmd: dotnet publish -c Release -r win-x64 -o win-x64 XboxWebApi.Cli + - cmd: 7z a XboxWebApiCli-%APPVEYOR_REPO_TAG_NAME%-windows-x64.zip %APPVEYOR_BUILD_FOLDER%\XboxWebApi.Cli\win-x64\* + +artifacts: + - path: "*.zip" + name: clientexe + type: Zip + deploy: -- provider: NuGet - api_key: - secure: wIdVJb80C4XWefa1hpb3XYrsOjoEjzZQ/pR+N/89qOoOH4elogXFPZabqNtdv72h - skip_symbols: false + - provider: NuGet + api_key: + secure: wIdVJb80C4XWefa1hpb3XYrsOjoEjzZQ/pR+N/89qOoOH4elogXFPZabqNtdv72h + skip_symbols: false + on: + appveyor_repo_tag: true + - provider: GitHub + description: "SmartGlass Authentication Cli" + artifact: clientexe + auth_token: + secure: qglMtUCbrzIn+36s7qWOPEj0HmJgs99bnzi4K8uYNPoxGW0qmJdOD1lmsa3TzGPn + draft: false + prerelease: false + tag: $(APPVEYOR_REPO_TAG_NAME) + on: + appveyor_repo_tag: true