Skip to content

Commit 74018fb

Browse files
committedMay 28, 2017
- Initial Project check-in
- Adding initial Authorization flow - Initial setup of Channels service
1 parent 6b80119 commit 74018fb

14 files changed

+938
-0
lines changed
 

‎.gitattributes

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
###############################################################################
2+
# Set default behavior to automatically normalize line endings.
3+
###############################################################################
4+
* text=auto
5+
6+
###############################################################################
7+
# Set default behavior for command prompt diff.
8+
#
9+
# This is need for earlier builds of msysgit that does not have it on by
10+
# default for csharp files.
11+
# Note: This is only used by command line
12+
###############################################################################
13+
#*.cs diff=csharp
14+
15+
###############################################################################
16+
# Set the merge driver for project and solution files
17+
#
18+
# Merging from the command prompt will add diff markers to the files if there
19+
# are conflicts (Merging from VS is not affected by the settings below, in VS
20+
# the diff markers are never inserted). Diff markers may cause the following
21+
# file extensions to fail to load in VS. An alternative would be to treat
22+
# these files as binary and thus will always conflict and require user
23+
# intervention with every merge. To do so, just uncomment the entries below
24+
###############################################################################
25+
#*.sln merge=binary
26+
#*.csproj merge=binary
27+
#*.vbproj merge=binary
28+
#*.vcxproj merge=binary
29+
#*.vcproj merge=binary
30+
#*.dbproj merge=binary
31+
#*.fsproj merge=binary
32+
#*.lsproj merge=binary
33+
#*.wixproj merge=binary
34+
#*.modelproj merge=binary
35+
#*.sqlproj merge=binary
36+
#*.wwaproj merge=binary
37+
38+
###############################################################################
39+
# behavior for image files
40+
#
41+
# image files are treated as binary by default.
42+
###############################################################################
43+
#*.jpg binary
44+
#*.png binary
45+
#*.gif binary
46+
47+
###############################################################################
48+
# diff behavior for common document formats
49+
#
50+
# Convert binary document formats to text before diffing them. This feature
51+
# is only available from the command line. Turn it on by uncommenting the
52+
# entries below.
53+
###############################################################################
54+
#*.doc diff=astextplain
55+
#*.DOC diff=astextplain
56+
#*.docx diff=astextplain
57+
#*.DOCX diff=astextplain
58+
#*.dot diff=astextplain
59+
#*.DOT diff=astextplain
60+
#*.pdf diff=astextplain
61+
#*.PDF diff=astextplain
62+
#*.rtf diff=astextplain
63+
#*.RTF diff=astextplain

‎.gitignore

+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
## Ignore Visual Studio temporary files, build results, and
2+
## files generated by popular Visual Studio add-ons.
3+
4+
# User-specific files
5+
*.suo
6+
*.user
7+
*.sln.docstates
8+
9+
# Visual Studio folders
10+
.vs/
11+
12+
# Unit Test results
13+
[Tt]estResults/
14+
15+
# Build results
16+
[Dd]ebug/
17+
[Dd]ebugPublic/
18+
[Rr]elease/
19+
x64/
20+
build/
21+
bld/
22+
[Bb]in/
23+
[Oo]bj/
24+
25+
# Roslyn cache directories
26+
*.ide/
27+
28+
# MSTest test Results
29+
[Tt]est[Rr]esult*/
30+
[Bb]uild[Ll]og.*
31+
32+
#NUNIT
33+
*.VisualState.xml
34+
TestResult.xml
35+
36+
# Build Results of an ATL Project
37+
[Dd]ebugPS/
38+
[Rr]eleasePS/
39+
dlldata.c
40+
41+
*_i.c
42+
*_p.c
43+
*_i.h
44+
*.ilk
45+
*.meta
46+
*.obj
47+
*.pch
48+
*.pdb
49+
*.pgc
50+
*.pgd
51+
*.rsp
52+
*.sbr
53+
*.tlb
54+
*.tli
55+
*.tlh
56+
*.tmp
57+
*.tmp_proj
58+
*.log
59+
*.vspscc
60+
*.vssscc
61+
.builds
62+
*.pidb
63+
*.svclog
64+
*.scc
65+
66+
# Chutzpah Test files
67+
_Chutzpah*
68+
69+
# Visual C++ cache files
70+
ipch/
71+
*.aps
72+
*.ncb
73+
*.opensdf
74+
*.sdf
75+
*.cachefile
76+
*.VC.db
77+
*.VC.VC.opendb
78+
79+
# Visual Studio profiler
80+
*.psess
81+
*.vsp
82+
*.vspx
83+
84+
# TFS 2012 Local Workspace
85+
$tf/
86+
87+
# Guidance Automation Toolkit
88+
*.gpState
89+
90+
# ReSharper is a .NET coding add-in
91+
_ReSharper*/
92+
*.[Rr]e[Ss]harper
93+
*.DotSettings.user
94+
95+
# JustCode is a .NET coding addin-in
96+
.JustCode
97+
98+
# TeamCity is a build add-in
99+
_TeamCity*
100+
101+
# DotCover is a Code Coverage Tool
102+
*.dotCover
103+
104+
# NCrunch
105+
_NCrunch_*
106+
.*crunch*.local.xml
107+
108+
# MightyMoose
109+
*.mm.*
110+
AutoTest.Net/
111+
112+
# Web workbench (sass)
113+
.sass-cache/
114+
115+
# Installshield output folder
116+
[Ee]xpress/
117+
118+
# DocProject is a documentation generator add-in
119+
DocProject/buildhelp/
120+
DocProject/Help/*.HxT
121+
DocProject/Help/*.HxC
122+
DocProject/Help/*.hhc
123+
DocProject/Help/*.hhk
124+
DocProject/Help/*.hhp
125+
DocProject/Help/Html2
126+
DocProject/Help/html
127+
128+
# Click-Once directory
129+
publish/
130+
131+
# Publish Web Output
132+
*.[Pp]ublish.xml
133+
*.azurePubxml
134+
## TODO: Comment the next line if you want to checkin your
135+
## web deploy settings but do note that will include unencrypted
136+
## passwords
137+
#*.pubxml
138+
139+
# NuGet Packages Directory
140+
packages/*
141+
## TODO: If the tool you use requires repositories.config
142+
## uncomment the next line
143+
#!packages/repositories.config
144+
145+
# Enable "build/" folder in the NuGet Packages folder since
146+
# NuGet packages use it for MSBuild targets.
147+
# This line needs to be after the ignore of the build folder
148+
# (and the packages folder if the line above has been uncommented)
149+
!packages/build/
150+
151+
# Windows Azure Build Output
152+
csx/
153+
*.build.csdef
154+
155+
# Windows Store app package directory
156+
AppPackages/
157+
158+
# Others
159+
sql/
160+
*.Cache
161+
ClientBin/
162+
[Ss]tyle[Cc]op.*
163+
~$*
164+
*~
165+
*.dbmdl
166+
*.dbproj.schemaview
167+
*.pfx
168+
*.publishsettings
169+
node_modules/
170+
171+
# RIA/Silverlight projects
172+
Generated_Code/
173+
174+
# Backup & report files from converting an old project file
175+
# to a newer Visual Studio version. Backup files are not needed,
176+
# because we have git ;-)
177+
_UpgradeReport_Files/
178+
Backup*/
179+
UpgradeLog*.XML
180+
UpgradeLog*.htm
181+
182+
# SQL Server files
183+
*.mdf
184+
*.ldf
185+
186+
# Business Intelligence projects
187+
*.rdl.data
188+
*.bim.layout
189+
*.bim_*.settings
190+
191+
# Microsoft Fakes
192+
FakesAssemblies/
193+
194+
# LightSwitch generated files
195+
GeneratedArtifacts/
196+
_Pvt_Extensions/
197+
ModelManifest.xml
198+
/BetterSkinnedModel/packages
199+
/SXTEngine/PlatformerGame/packages
200+
/3DTest/packages

‎Mixer Apps.sln

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.25420.1
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mixer.Base", "Mixer.Base\Mixer.Base.csproj", "{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mixer.UnitTests", "Mixer.UnitTests\Mixer.UnitTests.csproj", "{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal

‎Mixer.Base/API/ChannelsService.cs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Mixer.Base.Model;
2+
using Mixer.Base.Web;
3+
using Newtonsoft.Json.Linq;
4+
using System;
5+
using System.Net;
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
9+
namespace Mixer.Base.API
10+
{
11+
public static class ChannelsService
12+
{
13+
public static async Task<Channel> GetChannel(AuthorizationToken token, string channelName)
14+
{
15+
if (token == null)
16+
{
17+
throw new ArgumentException("Token is null");
18+
}
19+
20+
if (string.IsNullOrEmpty(channelName))
21+
{
22+
throw new ArgumentException("Channel Name must have a valid value");
23+
}
24+
25+
using (HttpClientWrapper client = new HttpClientWrapper(token))
26+
{
27+
HttpResponseMessage response = await client.GetAsync("channels/" + channelName);
28+
string result = await response.Content.ReadAsStringAsync();
29+
if (response.StatusCode == HttpStatusCode.OK)
30+
{
31+
JObject jobject = JObject.Parse(result);
32+
return null;
33+
}
34+
else
35+
{
36+
throw new HttpRequestException(string.Format("{0} ({1}) - {2}", (int)response.StatusCode, response.ReasonPhrase, result));
37+
}
38+
}
39+
}
40+
}
41+
}

‎Mixer.Base/Mixer.Base.csproj

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{3D2FD5B5-BEFD-414E-A79F-C26B6842691D}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>Mixer.Base</RootNamespace>
11+
<AssemblyName>Mixer.Base</AssemblyName>
12+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<DebugType>pdbonly</DebugType>
26+
<Optimize>true</Optimize>
27+
<OutputPath>bin\Release\</OutputPath>
28+
<DefineConstants>TRACE</DefineConstants>
29+
<ErrorReport>prompt</ErrorReport>
30+
<WarningLevel>4</WarningLevel>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
34+
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
35+
<Private>True</Private>
36+
</Reference>
37+
<Reference Include="System" />
38+
<Reference Include="System.Core" />
39+
<Reference Include="System.Xml.Linq" />
40+
<Reference Include="System.Data.DataSetExtensions" />
41+
<Reference Include="Microsoft.CSharp" />
42+
<Reference Include="System.Data" />
43+
<Reference Include="System.Net.Http" />
44+
<Reference Include="System.Xml" />
45+
</ItemGroup>
46+
<ItemGroup>
47+
<Compile Include="API\ChannelsService.cs" />
48+
<Compile Include="Model\Channel.cs" />
49+
<Compile Include="Web\AuthorizationToken.cs" />
50+
<Compile Include="Properties\AssemblyInfo.cs" />
51+
<Compile Include="Web\HttpClientWrapper.cs" />
52+
</ItemGroup>
53+
<ItemGroup>
54+
<None Include="packages.config" />
55+
</ItemGroup>
56+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
57+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
58+
Other similar extension points exist, see Microsoft.Common.targets.
59+
<Target Name="BeforeBuild">
60+
</Target>
61+
<Target Name="AfterBuild">
62+
</Target>
63+
-->
64+
</Project>

‎Mixer.Base/Model/Channel.cs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace Mixer.Base.Model
2+
{
3+
public class Channel
4+
{
5+
public uint id { get; set; }
6+
public uint userId { get; set; }
7+
public string name { get; set; }
8+
public string token { get; set; }
9+
10+
public bool featured { get; set; }
11+
public int featureLevel { get; set; }
12+
public bool partnered { get; set; }
13+
public bool suspended { get; set; }
14+
15+
public bool online { get; set; }
16+
public string audience { get; set; }
17+
public uint viewersTotal { get; set; }
18+
public uint viewersCurrent { get; set; }
19+
public uint numFollowers { get; set; }
20+
}
21+
}

‎Mixer.Base/Properties/AssemblyInfo.cs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("Mixer.Base")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("Mixer.Base")]
13+
[assembly: AssemblyCopyright("Copyright © 2017")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("3d2fd5b5-befd-414e-a79f-c26b6842691d")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

‎Mixer.Base/Web/AuthorizationToken.cs

+268
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
using Mixer.Base.Web;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Net;
8+
using System.Net.Http;
9+
using System.Threading.Tasks;
10+
11+
namespace Mixer.Base
12+
{
13+
public enum ClientScopeEnum
14+
{
15+
achievement__view__self,
16+
channel__analytics,
17+
channel__analytics__self,
18+
channel__costream__self,
19+
channel__deleteBanner,
20+
channel__deleteBanner__self,
21+
channel__details__self,
22+
channel__follow__self,
23+
channel__partnership,
24+
channel__partnership__self,
25+
channel__streamKey__self,
26+
channel__update__self,
27+
chat__bypass_links,
28+
chat__bypass_slowchat,
29+
chat__change_ban,
30+
chat__change_role,
31+
chat__chat,
32+
chat__clear_messages,
33+
chat__connect,
34+
chat__edit_options,
35+
chat__giveaway_start,
36+
chat__poll_start,
37+
chat__poll_vote,
38+
chat__purge,
39+
chat__remove_message,
40+
chat__timeout,
41+
chat__view_deleted,
42+
chat__whisper,
43+
interactive__manage__self,
44+
interactive__robot__self,
45+
invoice__view__self,
46+
log__view__self,
47+
notification__update__self,
48+
notification__view__self,
49+
recording__manage__self,
50+
redeemable__create__self,
51+
redeemable__redeem__self,
52+
redeemable__view__self,
53+
resource__find__self,
54+
subscription__cancel__self,
55+
subscription__create__self,
56+
subscription__renew__self,
57+
subscription__view__self,
58+
team__administer,
59+
team__manage__self,
60+
transaction__cancel__self,
61+
transaction__view__self,
62+
type__viewHidden,
63+
user__analytics__self,
64+
user__details__self,
65+
user__getDiscordInvite__self,
66+
user__log__self,
67+
user__notification__self,
68+
user__seen__self,
69+
user__update__self,
70+
user__updatePassword__self,
71+
}
72+
73+
public class ShortCode
74+
{
75+
public string code { get; set; }
76+
public string handle { get; set; }
77+
public uint expires_in { get; set; }
78+
}
79+
80+
public class AuthorizationToken
81+
{
82+
public static async Task<ShortCode> GenerateShortCode(string clientID, IEnumerable<ClientScopeEnum> scopes)
83+
{
84+
if (string.IsNullOrEmpty(clientID))
85+
{
86+
throw new ArgumentException("Client ID must have a valid value");
87+
}
88+
89+
if (scopes.Count() == 0)
90+
{
91+
throw new ArgumentException("At least one scope must be specified");
92+
}
93+
94+
using (HttpClientWrapper client = new HttpClientWrapper())
95+
{
96+
FormUrlEncodedContent content = new FormUrlEncodedContent(new[]
97+
{
98+
new KeyValuePair<string, string>("client_id", clientID),
99+
new KeyValuePair<string, string>("client_secret", null),
100+
new KeyValuePair<string, string>("scope", AuthorizationToken.ConvertClientScopesToString(scopes)),
101+
});
102+
103+
HttpResponseMessage response = await client.PostAsync("oauth/shortcode", content);
104+
if (response.StatusCode == HttpStatusCode.OK)
105+
{
106+
string result = await response.Content.ReadAsStringAsync();
107+
return JsonConvert.DeserializeObject<ShortCode>(result);
108+
}
109+
else
110+
{
111+
throw new HttpRequestException(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
112+
}
113+
}
114+
}
115+
116+
public static async Task<string> ValidateShortCode(ShortCode shortCode)
117+
{
118+
if (shortCode == null)
119+
{
120+
throw new ArgumentException("Short Code is null");
121+
}
122+
123+
for (int i = 0; i < shortCode.expires_in; i++)
124+
{
125+
using (HttpClientWrapper client = new HttpClientWrapper())
126+
{
127+
HttpResponseMessage response = await client.GetAsync("oauth/shortcode/check/" + shortCode.handle);
128+
if (response.StatusCode == HttpStatusCode.OK)
129+
{
130+
string result = await response.Content.ReadAsStringAsync();
131+
JObject jobject = JObject.Parse(result);
132+
return (string)jobject["code"];
133+
}
134+
}
135+
await Task.Delay(1000);
136+
}
137+
return null;
138+
}
139+
140+
public static async Task<AuthorizationToken> GetAuthorizationToken(string clientID, string authorizationCode)
141+
{
142+
if (string.IsNullOrEmpty(clientID))
143+
{
144+
throw new ArgumentException("Client ID must have a valid value");
145+
}
146+
147+
if (string.IsNullOrEmpty(authorizationCode))
148+
{
149+
throw new ArgumentException("Authorization Code must have a valid value");
150+
}
151+
152+
using (HttpClientWrapper client = new HttpClientWrapper())
153+
{
154+
FormUrlEncodedContent content = new FormUrlEncodedContent(new[]
155+
{
156+
new KeyValuePair<string, string>("grant_type", "authorization_code"),
157+
new KeyValuePair<string, string>("client_id", clientID),
158+
new KeyValuePair<string, string>("code", authorizationCode),
159+
});
160+
161+
HttpResponseMessage response = await client.PostAsync("oauth/token", content);
162+
if (response.StatusCode == HttpStatusCode.OK)
163+
{
164+
string result = await response.Content.ReadAsStringAsync();
165+
JObject jobject = JObject.Parse(result);
166+
return new AuthorizationToken(clientID, authorizationCode, (string)jobject["access_token"], (string)jobject["refresh_token"], (int)jobject["expires_in"]);
167+
}
168+
else
169+
{
170+
throw new HttpRequestException(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
171+
}
172+
}
173+
}
174+
175+
private static string ConvertClientScopesToString(IEnumerable<ClientScopeEnum> scopes)
176+
{
177+
string result = "";
178+
179+
foreach (ClientScopeEnum scope in scopes)
180+
{
181+
string enumName = Enum.GetName(typeof(ClientScopeEnum), scope);
182+
if (string.IsNullOrEmpty(enumName))
183+
{
184+
throw new ArgumentException("Invalid client scope specified: " + scope);
185+
}
186+
enumName = enumName.Replace("__", ":");
187+
result += enumName + " ";
188+
}
189+
190+
if (result.Length > 0)
191+
{
192+
result = result.Substring(0, result.Length - 1);
193+
}
194+
195+
return result;
196+
}
197+
198+
public DateTimeOffset Expiration { get; private set; }
199+
200+
internal string AccessToken { get; private set; }
201+
202+
private string clientID;
203+
private string authorizationCode;
204+
private string refreshToken;
205+
206+
private AuthorizationToken(string clientID, string authorizationCode, string accessToken, string refreshToken, int expiresIn)
207+
{
208+
if (string.IsNullOrEmpty(clientID))
209+
{
210+
throw new ArgumentException("Client ID must have a valid value");
211+
}
212+
213+
if (string.IsNullOrEmpty(authorizationCode))
214+
{
215+
throw new ArgumentException("Authorization Code must have a valid value");
216+
}
217+
218+
if (string.IsNullOrEmpty(accessToken))
219+
{
220+
throw new ArgumentException("Access Token must have a valid value");
221+
}
222+
223+
if (string.IsNullOrEmpty(refreshToken))
224+
{
225+
throw new ArgumentException("Refresh Token must have a valid value");
226+
}
227+
228+
if (expiresIn <= 0)
229+
{
230+
throw new ArgumentException("Expires In must be a valid value");
231+
}
232+
233+
this.clientID = clientID;
234+
this.authorizationCode = authorizationCode;
235+
this.AccessToken = accessToken;
236+
this.refreshToken = refreshToken;
237+
this.Expiration = DateTimeOffset.Now.AddSeconds(expiresIn);
238+
}
239+
240+
public async Task RefreshToken()
241+
{
242+
using (HttpClientWrapper client = new HttpClientWrapper())
243+
{
244+
FormUrlEncodedContent content = new FormUrlEncodedContent(new[]
245+
{
246+
new KeyValuePair<string, string>("grant_type", "refresh_token"),
247+
new KeyValuePair<string, string>("client_id", this.clientID),
248+
new KeyValuePair<string, string>("refresh_token", this.refreshToken),
249+
});
250+
251+
HttpResponseMessage response = await client.PostAsync("oauth/token", content);
252+
if (response.StatusCode == HttpStatusCode.OK)
253+
{
254+
string result = await response.Content.ReadAsStringAsync();
255+
JObject jobject = JObject.Parse(result);
256+
257+
this.AccessToken = (string)jobject["access_token"];
258+
this.refreshToken = (string)jobject["refresh_token"];
259+
this.Expiration = DateTimeOffset.Now.AddSeconds((int)jobject["expires_in"]);
260+
}
261+
else
262+
{
263+
throw new HttpRequestException(string.Format("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase));
264+
}
265+
}
266+
}
267+
}
268+
}

‎Mixer.Base/Web/HttpClientWrapper.cs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Net.Http.Headers;
4+
5+
namespace Mixer.Base.Web
6+
{
7+
public class HttpClientWrapper : HttpClient
8+
{
9+
private const string MixerRestAPIBaseAddress = "https://mixer.com/api/v1/";
10+
11+
public HttpClientWrapper()
12+
: base()
13+
{
14+
this.BaseAddress = new Uri(MixerRestAPIBaseAddress);
15+
this.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
16+
}
17+
18+
public HttpClientWrapper(AuthorizationToken authorizationToken)
19+
: this()
20+
{
21+
this.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authorizationToken.AccessToken);
22+
}
23+
}
24+
}

‎Mixer.Base/packages.config

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net452" />
4+
</packages>
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Mixer.Base;
3+
using Mixer.Base.API;
4+
using Mixer.Base.Model;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Diagnostics;
8+
9+
namespace Mixer.UnitTests
10+
{
11+
[TestClass]
12+
public class AuthorizationUnitTests
13+
{
14+
[TestMethod]
15+
public void AuthorizeViaShortCode()
16+
{
17+
try
18+
{
19+
string clientID = "a95a8520f369fdd46d08aba183953c5c8a4c3822affec476";
20+
21+
ShortCode shortCode = AuthorizationToken.GenerateShortCode("a95a8520f369fdd46d08aba183953c5c8a4c3822affec476", new List<ClientScopeEnum>() { ClientScopeEnum.chat__chat }).Result;
22+
23+
Assert.IsNotNull(shortCode);
24+
Trace.WriteLine("Short Code: " + shortCode.code);
25+
26+
string code = AuthorizationToken.ValidateShortCode(shortCode).Result;
27+
28+
Assert.IsNotNull(code);
29+
Assert.AreNotEqual(code, string.Empty);
30+
31+
AuthorizationToken token = AuthorizationToken.GetAuthorizationToken(clientID, code).Result;
32+
33+
Assert.IsNotNull(token);
34+
35+
token.RefreshToken().Wait();
36+
37+
Channel channel = ChannelsService.GetChannel(token, "GlockGirl").Result;
38+
}
39+
catch (Exception ex)
40+
{
41+
Assert.Fail(ex.Message);
42+
}
43+
}
44+
}
45+
}

‎Mixer.UnitTests/ChannelUnitTests.cs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
3+
namespace Mixer.UnitTests
4+
{
5+
/// <summary>
6+
/// Summary description for ChannelUnitTests
7+
/// </summary>
8+
[TestClass]
9+
public class ChannelUnitTests
10+
{
11+
[TestMethod]
12+
public void TestMethod1()
13+
{
14+
}
15+
}
16+
}
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6+
<ProjectGuid>{6CE0ED6C-9AE0-47C6-973B-8A50CF658482}</ProjectGuid>
7+
<OutputType>Library</OutputType>
8+
<AppDesignerFolder>Properties</AppDesignerFolder>
9+
<RootNamespace>Mixer.UnitTests</RootNamespace>
10+
<AssemblyName>Mixer.UnitTests</AssemblyName>
11+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
12+
<FileAlignment>512</FileAlignment>
13+
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
14+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
15+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
16+
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
17+
<IsCodedUITest>False</IsCodedUITest>
18+
<TestProjectType>UnitTest</TestProjectType>
19+
</PropertyGroup>
20+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
21+
<DebugSymbols>true</DebugSymbols>
22+
<DebugType>full</DebugType>
23+
<Optimize>false</Optimize>
24+
<OutputPath>bin\Debug\</OutputPath>
25+
<DefineConstants>DEBUG;TRACE</DefineConstants>
26+
<ErrorReport>prompt</ErrorReport>
27+
<WarningLevel>4</WarningLevel>
28+
</PropertyGroup>
29+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
30+
<DebugType>pdbonly</DebugType>
31+
<Optimize>true</Optimize>
32+
<OutputPath>bin\Release\</OutputPath>
33+
<DefineConstants>TRACE</DefineConstants>
34+
<ErrorReport>prompt</ErrorReport>
35+
<WarningLevel>4</WarningLevel>
36+
</PropertyGroup>
37+
<ItemGroup>
38+
<Reference Include="System" />
39+
</ItemGroup>
40+
<Choose>
41+
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
42+
<ItemGroup>
43+
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
44+
</ItemGroup>
45+
</When>
46+
<Otherwise>
47+
<ItemGroup>
48+
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
49+
<Private>False</Private>
50+
</Reference>
51+
</ItemGroup>
52+
</Otherwise>
53+
</Choose>
54+
<ItemGroup>
55+
<Compile Include="AuthorizationUnitTests.cs" />
56+
<Compile Include="ChannelUnitTests.cs" />
57+
<Compile Include="Properties\AssemblyInfo.cs" />
58+
</ItemGroup>
59+
<ItemGroup>
60+
<ProjectReference Include="..\Mixer.Base\Mixer.Base.csproj">
61+
<Project>{3d2fd5b5-befd-414e-a79f-c26b6842691d}</Project>
62+
<Name>Mixer.Base</Name>
63+
</ProjectReference>
64+
</ItemGroup>
65+
<Choose>
66+
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
67+
<ItemGroup>
68+
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
69+
<Private>False</Private>
70+
</Reference>
71+
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
72+
<Private>False</Private>
73+
</Reference>
74+
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
75+
<Private>False</Private>
76+
</Reference>
77+
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
78+
<Private>False</Private>
79+
</Reference>
80+
</ItemGroup>
81+
</When>
82+
</Choose>
83+
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
84+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
85+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
86+
Other similar extension points exist, see Microsoft.Common.targets.
87+
<Target Name="BeforeBuild">
88+
</Target>
89+
<Target Name="AfterBuild">
90+
</Target>
91+
-->
92+
</Project>
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("Mixer.UnitTests")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("Mixer.UnitTests")]
13+
[assembly: AssemblyCopyright("Copyright © 2017")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("6ce0ed6c-9ae0-47c6-973b-8a50cf658482")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

0 commit comments

Comments
 (0)
Please sign in to comment.