Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
PKCE Auth fully working with XML encryption.
Browse files Browse the repository at this point in the history
  • Loading branch information
zkhcohen committed Apr 10, 2021
1 parent bca2f60 commit 1460a63
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 21 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
CHANGE LOG:

Beta 2.0: Improved performance. Removed 500 album restriction. Added automatic prompt to re-authenticate if computer resumes from sleep.
Beta 2.0.2: Fixed error log spam.
Release 2.0: Improved performance. Removed 500 album restriction. Added automatic prompt to re-authenticate if computer resumes from sleep.
Release 2.0.2: Fixed error log spam.
Beta 3.1: Upgraded all API methods to 6.x.x spec. Implemented PKCE auth method with token persistence and automatic renewal. General speed improvements.
Binary file modified Plugins/SpotifyAPI.Web.Auth.dll
Binary file not shown.
Binary file modified Plugins/SpotifyAPI.Web.dll
Binary file not shown.
Binary file modified Plugins/mb_Spotify-Plugin.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Let me know if you encounter any bugs - "ZKHCOHEN" on the MusicBee Forums.

KNOWN ISSUES:

The Spotify API is (incorrectly) reporting the follow error in the MusicBee ErrorLog.dat file:
The Spotify API is (incorrectly) reporting the following error in the MusicBee ErrorLog.dat file:

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property.
As a result, the unobserved exception was rethrown by the finalizer thread. ---> SpotifyAPI.Web.APIException: invalid_grant
89 changes: 89 additions & 0 deletions Source Files/Crypt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace MusicBeePlugin
{
public partial class Plugin
{
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
{
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");

XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;

if (elementToEncrypt == null)
{
throw new XmlException("The specified element was not found");
}
Aes sessionKey = null;

try
{
EncryptedXml eXml = new EncryptedXml();
EncryptedData edElement = new EncryptedData();
EncryptedKey ek = new EncryptedKey();
DataReference dRef = new DataReference();
KeyInfoName kin = new KeyInfoName();

sessionKey = Aes.Create();

byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);

edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);

ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
dRef.Uri = "#" + EncryptionElementID;
ek.AddReference(dRef);
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
kin.Value = KeyName;
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;

EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
catch (Exception e)
{
throw e;
}
finally
{
if (sessionKey != null)
{
sessionKey.Clear();
}
}
}

public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
{
if (Doc == null)
throw new ArgumentNullException("Doc");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");

EncryptedXml exml = new EncryptedXml(Doc);

exml.AddKeyNameMapping(KeyName, Alg);
exml.DecryptDocument();
}

}
}
20 changes: 15 additions & 5 deletions Source Files/PanelInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Collections.Generic;
using Microsoft.Win32;
using System.Security.Cryptography;

namespace MusicBeePlugin
{
Expand All @@ -19,6 +18,10 @@ public partial class Plugin
private static string _searchTerm;
private bool _runOnce = true;
Font largeBold, smallRegular, smallBold;
private RSACryptoServiceProvider _rsaKey;

// Create a new CspParameters object to specify a key container.
CspParameters _cspParams = new CspParameters();

public PluginInfo Initialise(IntPtr apiInterfacePtr)
{
Expand All @@ -30,15 +33,21 @@ public PluginInfo Initialise(IntPtr apiInterfacePtr)
about.Author = "zkhcohen";
about.TargetApplication = "Spotify Plugin";
about.Type = PluginType.PanelView;
about.VersionMajor = 2;
about.VersionMajor = 3;
about.VersionMinor = 0;
about.Revision = 2;
about.Revision = 5;
about.MinInterfaceVersion = MinInterfaceVersion;
about.MinApiRevision = MinApiRevision;
about.ReceiveNotifications = (ReceiveNotificationFlags.PlayerEvents | ReceiveNotificationFlags.TagEvents);
about.ConfigurationPanelHeight = 0;

_path = mbApiInterface.Setting_GetPersistentStoragePath() + @"token.txt";
_path = mbApiInterface.Setting_GetPersistentStoragePath() + "token.xml";

_cspParams.KeyContainerName = "SPOTIFY_XML_ENC_RSA_KEY";

// Create a new RSA key and save it in the container. This key will encrypt
// a symmetric key, which will then be encrypted in the XML document.
_rsaKey = new RSACryptoServiceProvider(_cspParams);

//SystemEvents.PowerModeChanged += OnPowerChange;

Expand Down Expand Up @@ -193,6 +202,7 @@ public List<ToolStripItem> GetMenuItems()

public void reAuthSpotify(object sender, EventArgs e)
{
File.Delete(_path);
SpotifyWebAuth();
_trackMissing = 1;
panel.Invalidate();
Expand Down
8 changes: 4 additions & 4 deletions Source Files/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
[assembly: AssemblyTitle("mb_Spotify_Plugin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Zachary Cohen")]
[assembly: AssemblyCompany("zkhcohen")]
[assembly: AssemblyProduct("mb_Spotify_Plugin")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.2.0")]
[assembly: AssemblyFileVersion("2.0.2.0")]
[assembly: AssemblyVersion("3.0.5.0")]
[assembly: AssemblyFileVersion("3.0.5.0")]
52 changes: 43 additions & 9 deletions Source Files/SpotifyIntegration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;
using System.Security.Cryptography;

namespace MusicBeePlugin
{
Expand All @@ -20,22 +21,46 @@ public partial class Plugin
private static string _title, _album, _artist, _trackID, _albumID, _artistID, _imageURL, _path;
private static string _clientID = "9076681768d94feda885a7b5eced926d";

public static void SerializeConfig(PKCETokenResponse data, string path)
public void SerializeConfig(PKCETokenResponse data, string path, RSACryptoServiceProvider rsaKey)
{

using (StreamWriter file = new StreamWriter(path, false))
{
XmlSerializer controlsDefaultsSerializer = new XmlSerializer(typeof(PKCETokenResponse));
controlsDefaultsSerializer.Serialize(file, data);
file.Close();
}

try
{
// Encrypt
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(path);
Encrypt(xmlDoc, "AccessToken", "AccessToken", rsaKey, "rsaKey");
Encrypt(xmlDoc, "RefreshToken", "RefreshToken", _rsaKey, "rsaKey");
xmlDoc.Save(path);

}
catch (Exception e)
{
Console.WriteLine(e.Message);
}

}

public static PKCETokenResponse DeserializeConfig(string path)
public PKCETokenResponse DeserializeConfig(string path, RSACryptoServiceProvider rsaKey)
{

try
{
// Decrypt
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(path);
Decrypt(xmlDoc, rsaKey, "rsaKey");
xmlDoc.Save(path);

// Deserialize
StreamReader file = new StreamReader(path);
XmlSerializer xSerial = new XmlSerializer(typeof(PKCETokenResponse));
object oData = xSerial.Deserialize(file);
Expand All @@ -45,10 +70,19 @@ public static PKCETokenResponse DeserializeConfig(string path)
}
catch (Exception e)
{

Console.Write(e.Message);
return null;
}
finally
{
// Encrypt
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(path);
Encrypt(xmlDoc, "AccessToken", "AccessToken", rsaKey, "rsaKey");
Encrypt(xmlDoc, "RefreshToken", "RefreshToken", rsaKey, "rsaKey");
xmlDoc.Save(path);
}
}

//static void WriteOutput(PKCETokenResponse InitialToken)
Expand All @@ -64,13 +98,13 @@ public static PKCETokenResponse DeserializeConfig(string path)
//}


static async void SpotifyWebAuth()
async void SpotifyWebAuth()
{
try
{
if(File.Exists(_path))
{
var token_response = DeserializeConfig(_path);
var token_response = DeserializeConfig(_path, _rsaKey);

//WriteOutput(token_response);

Expand All @@ -80,7 +114,7 @@ static async void SpotifyWebAuth()
.WithAuthenticator(authenticator);
_spotify = new SpotifyClient(config);

SerializeConfig(token_response, _path);
SerializeConfig(token_response, _path, _rsaKey);

//WriteOutput(token_response);

Expand Down Expand Up @@ -131,7 +165,7 @@ static async void SpotifyWebAuth()
_spotify = new SpotifyClient(config);
//WriteOutput(initialResponse);
SerializeConfig(initialResponse, _path);
SerializeConfig(initialResponse, _path, _rsaKey);
};
await server.Start();

Expand Down
2 changes: 2 additions & 0 deletions Source Files/mb_Spotify-Plugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Security" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
Expand All @@ -50,6 +51,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Crypt.cs" />
<Compile Include="PanelInterface.cs" />
<Compile Include="MusicBeeInterface.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down

0 comments on commit 1460a63

Please sign in to comment.