diff --git a/.gitignore b/.gitignore index eac73b6c..9b2b39ad 100644 --- a/.gitignore +++ b/.gitignore @@ -196,7 +196,7 @@ Setup/outlook_addin_with_keyring-cache/ # ========================== -# Enable Build folder for Nuget packages +# Enable Build folder for Nuget packages # ========================== !Nuget/*/build/ @@ -206,13 +206,14 @@ Setup/outlook_addin_with_keyring-cache/ # Config files # ========================== -SDK/Source/Virgil.SDK.Tests/App.config -SDK/Source/Virgil.SDK.Tests/App_Prod.config -SDK/Source/Virgil.SDK.Tests/App_Stg.config - +SDK/Source/Virgil.SDK.Tests.Shared/App.config +SDK/Source/Virgil.SDK.Tests.Shared/App_Prod.config +SDK/Source/Virgil.SDK.Tests.Shared/App_Stg.config +SDK/Source/.vs/ Nuget/__pycache__ Nuget/output +.idea/ # ========================== # MacOS @@ -221,3 +222,16 @@ Nuget/output *.DS_Store /doc/ myresults.xml +/docs/ + +#============================ +vs external project for c# 2.0 +#============================ +SDK/Source/Virgil.SDK.Shared/Crypto/Crypto.csproj +SDK/Source/Virgil.SDK.Shared/Crypto/Crypto.sln +SDK/Source/Virgil.SDK.Shared/Crypto/app.config +SDK/Source/Virgil.SDK.Shared/Crypto/packages.config +app.config +app-prod.config +# Studio +*.userprefs diff --git a/LICENSE.md b/LICENSE.md index 6348eb78..099be9b0 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,7 @@ -# Copyright 2017 Virgil Security +The BSD 3-Clause License (BSD) + +Copyright (c) 2018, Virgil Security, Inc. +All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Nuget/CryptoLib/Package.nuspec b/Nuget/CryptoLib/Package.nuspec index c4d99eed..94fb79e1 100644 --- a/Nuget/CryptoLib/Package.nuspec +++ b/Nuget/CryptoLib/Package.nuspec @@ -28,7 +28,7 @@ https://avatars0.githubusercontent.com/u/9740508 false http://opensource.org/licenses/Apache-2.0 - © 2016 Virgil Security, Inc. + © 2018 Virgil Security, Inc. diff --git a/Nuget/virgil-crypto-api.py b/Nuget/virgil-crypto-api.py new file mode 100644 index 00000000..fc702539 --- /dev/null +++ b/Nuget/virgil-crypto-api.py @@ -0,0 +1,9 @@ +import msbuilder + +proj = r'..\SDK\Source\Virgil.CryptoApi\Virgil.CryptoAPI.csproj' +spec = r'..\SDK\Source\Virgil.CryptoApi\Virgil.CryptoAPI.spec' +output = r'.\output' + +builder = msbuilder.MsBuilder() +builder.build(proj) +builder.pack(proj, output) \ No newline at end of file diff --git a/Nuget/virgil-crypto-impl.py b/Nuget/virgil-crypto-impl.py new file mode 100644 index 00000000..7f5de7f8 --- /dev/null +++ b/Nuget/virgil-crypto-impl.py @@ -0,0 +1,9 @@ +import msbuilder + +proj = r'..\..\virgil-sdk-crypto-net\Virgil.CryptoImpl\Virgil.CryptoImpl.csproj' +spec = r'..\..\virgil-sdk-crypto-net\Virgil.CryptoImpl\Virgil.CryptoImpl.nuspec' +output = r'.\output' + +builder = msbuilder.MsBuilder() +builder.build(proj) +builder.pack(proj, output) \ No newline at end of file diff --git a/Nuget/virgil-sdk-contracts.py b/Nuget/virgil-sdk-contracts.py deleted file mode 100644 index 1c820172..00000000 --- a/Nuget/virgil-sdk-contracts.py +++ /dev/null @@ -1,8 +0,0 @@ -import msbuilder - -proj = r'..\SDK\Source\Virgil.SDK.Contracts\Virgil.SDK.Contracts.csproj' -output = r'.\output' - -builder = msbuilder.MsBuilder() -builder.build(proj) -builder.pack(proj, output) \ No newline at end of file diff --git a/Nuget/virgil-sdk.py b/Nuget/virgil-sdk.py index c028c7b9..2bc99a6e 100644 --- a/Nuget/virgil-sdk.py +++ b/Nuget/virgil-sdk.py @@ -1,6 +1,8 @@ import msbuilder proj = r'..\SDK\Source\Virgil.SDK.NetFx\Virgil.SDK.NetFx.csproj' +spec = r'..\SDK\Source\Virgil.SDK.NetFx\Virgil.SDK.NetFx.nuspec' +nuget = r'C:\Users\Vasilina\Documents\projects\sdk-net2\virgil-sdk-net\SDK\Source\.nuget\NuGet.exe' output = r'.\output' builder = msbuilder.MsBuilder() diff --git a/README.md b/README.md index a44a2120..3346400d 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,146 @@ -# Virgil Security .NET/C# SDK +# Virgil Security .NET/C# SDK [![Build status](https://ci.appveyor.com/api/projects/status/kqs4lqw426gbpccm/branch/release?svg=true)](https://ci.appveyor.com/project/unlim-it/virgil-sdk-net/branch/release) [![Nuget package](https://img.shields.io/nuget/v/Virgil.SDK.svg)](https://www.nuget.org/packages/Virgil.SDK/) +[![GitHub license](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://github.com/VirgilSecurity/virgil/blob/master/LICENSE) + + +[Introduction](#installation) | [SDK Features](#sdk-features) | [Installation](#installation) | [Usage Examples](#usage-examples) | [Docs](#docs) | [Support](#support) -[Installation](#installation) | [Encryption Example](#encryption-example) | [Initialization](#initialization) | [Documentation](#documentation) | [Reference API][_reference_api] | [Support](#support) [Virgil Security](https://virgilsecurity.com) provides a set of APIs for adding security to any application. In a few simple steps you can encrypt communication, securely store data, provide passwordless login, and ensure data integrity. -For a full overview head over to our .NET/C# [Get Started][_getstarted] guides. +The Virgil SDK allows developers to get up and running with Virgil API quickly and add full end-to-end security to their existing digital solutions to become HIPAA and GDPR compliant and more. -## Installation +## SDK Features +- communicate with [Virgil Cards Service][_cards_service] +- manage users' Public Keys +- store private keys in secure local storage +- use Virgil [Crypto library][_virgil_crypto] +- use your own Crypto -The Virgil .NET SDK is provided as a package named *Virgil.SDK*. The package is distributed via NuGet package management system. -The package is available for .NET Framework 4.5 and newer. -Installing the package +## Installation -1. Use NuGet Package Manager (Tools -> Library Package Manager -> Package Manager Console) -2. Run `PM> Install-Package Virgil.SDK` +The Virgil .NET SDK is provided as a package named Virgil.SDK. The package is distributed via [NuGet package](https://docs.microsoft.com/en-us/nuget/quickstart/use-a-package) management system. -__Next:__ [Get Started with the .NET/C# SDK][_getstarted]. +The package is available for .NET Framework 4.5 and newer. -## Encryption Example +Installing the package using Package Manager Console: -Virgil Security makes it super easy to add encryption to any application. With our SDK you create a public [__Virgil Card__][_guide_virgil_cards] for every one of your users and devices. With these in place you can easily encrypt any data in the client. +```bash +Run PM> Install-Package Virgil.SDK +``` -```csharp -// find Alice's card(s) -var aliceCards = await virgil.Cards.FindAsync("alice"); +## Usage Examples -// encrypt the message using Alice's cards -var message = "Hello Alice!"; -var encryptedMessage = aliceCards.Encrypt(message); +#### Generate and publish user's Cards with Public Keys inside on Cards Service +Use the following lines of code to create and publish a user's Card with Public Key inside on Virgil Cards Service: -// transmit the message with your preferred technology -this.TransmitMessage(encryptedMessage.ToString(StringEncoding.Base64)); -``` +```cs +using Virgil.CryptoImpl; +using Virgil.SDK; -The receiving user then uses their stored __private key__ to decrypt the message. +var crypto = new VirgilCrypto(); +// generate a key pair +var keyPair = crypto.GenerateKeys(); -```csharp -// load Alice's Key from storage. -var aliceKey = virgil.Keys.Load("alice_key_1", "mypassword"); +// save a private key into key storage +privateKeyStorage.Store(keyPair.PrivateKey, "Alice"); -// decrypt the message using the key -var originalMessage = aliceKey.Decrypt(transferData).ToString(); +// publish user's on the Cards Service +var card = await cardManager.PublishCardAsync( + new CardParams() + { + PublicKey = keyPair.PublicKey, + PrivateKey = keyPair.PrivateKey, + }); ``` -__Next:__ To [get you properly started][_guide_encryption] you'll need to know how to create and store Virgil Cards. Our [Get Started guide][_guide_encryption] will get you there all the way. +#### Sign then encrypt data + +Virgil SDK lets you use a user's Private key and his or her Cards to sign, then encrypt any kind of data. -__Also:__ [Encrypted communication][_getstarted_encryption] is just one of the few things our SDK can do. Have a look at our guides on [Encrypted Storage][_getstarted_storage], [Data Integrity][_getstarted_data_integrity] and [Passwordless Login][_getstarted_passwordless_login] for more information. +In the following example, we load a Private Key from a customized Key Storage and get recipient's Card from the Virgil Cards Services. Recipient's Card contains a Public Key on which we will encrypt the data and verify a signature. -## Initialization +```cs +using Virgil.CryptoImpl; +using Virgil.SDK; -To use this SDK you need to [sign up for an account](https://developer.virgilsecurity.com/account/signup) and create your first __application__. Make sure to save the __app id__, __private key__ and it's __password__. After this, create an __application token__ for your application to make authenticated requests from your clients. +// prepare a message +var messageToEncrypt = "Hello, Bob!"; +var dataToEncrypt = Bytes.FromString(messageToEncrypt); -To initialize the SDK on the client side you will only need the __access token__ you created. +// prepare a user's private key +var (alicePrivateKey, alicePrivateKeyAdditionalData) = privateKeyStorage.Load("Alice"); -```csharp -var virgil = new VirgilApi("[ACCESS_TOKEN]"); +// using cardManager search for Bob's cards on Cards Service +var cards = await cardManager.SearchCardsAsync("Bob"); +var bobRelevantCardsPublicKeys = cards.Select(x => x.PublicKey).ToArray(); + +// sign a message with a private key then encrypt using Bob's public keys +var encryptedData = crypto.SignThenEncrypt(dataToEncrypt, alicePrivateKey, bobRelevantCardsPublicKeys); ``` -> __Note:__ this client will have limited capabilities. For example, it will be able to generate new __Cards__ but it will need a server-side client to transmit these to Virgil. +#### Decrypt then verify data +Once the Users receive the signed and encrypted message, they can decrypt it with their own Private Key and verify signature with a Sender's Card: + +```cs +using Virgil.CryptoImpl; +using Virgil.SDK; -To initialize the SDK on the server side we will need the __access token__, __app id__ and the __App Key__ you created on the [Developer Dashboard](https://developer.virgilsecurity.com/account/dashboard). +// prepare a user's private key +var (bobPrivateKey, bobPrivateKeyAdditionalData) = privateKeyStorage.Load("Bob"); -```csharp -var context = new VirgilApiContext -{ - AccessToken = "[YOUR_ACCESS_TOKEN_HERE]", - Credentials = new AppCredentials - { - AppId = "[YOUR_APP_ID_HERE]", - AppKeyData = VirgilBuffer.FromFile("[YOUR_APP_KEY_PATH_HERE]"), - AppKeyPassword = "[YOUR_APP_KEY_PASSWORD_HERE]" - } -}; +// using cardManager search for Alice's cards on Cards Service +var cards = await cardManager.SearchCardsAsync("Alice"); +var aliceRelevantCardsPublicKeys = cards.Select(x => x.PublicKey).ToArray(); -var virgil = new VirgilApi(context); +// decrypt with a private key and verify using one of Alice's public keys +var decryptedData = crypto.DecryptThenVerify(encryptedData, bobPrivateKey, aliceRelevantCardsPublicKeys); ``` -Next: [Learn more about our the different ways of initializing the .NET/C# SDK][_guide_initialization] in our documentation. +## Docs +Virgil Security has a powerful set of APIs, and the documentation below can get you started today. -## Documentation +In order to use the Virgil SDK with your application, you will need to first configure your application. By default, the SDK will attempt to look for Virgil-specific settings in your application but you can change it during SDK configuration. -Virgil Security has a powerful set of APIs, and the documentation is there to get you started today. +* [Configure the SDK][_configure_sdk] documentation + * [Setup authentication][_setup_authentication] to make API calls to Virgil Services + * [Setup Card Manager][_card_manager] to manage user's Public Keys + * [Setup Card Verifier][_card_verifier] to verify signatures inside of user's Card + * [Setup Key storage][_key_storage] to store Private Keys + * [Setup your own Crypto library][_own_crypto] inside of the SDK +* [More usage examples][_more_examples] + * [Create & publish a Card][_create_card] that has a Public Key on Virgil Cards Service + * [Search user's Card by user's identity][_search_card] + * [Get user's Card by its ID][_get_card] + * [Use Card for crypto operations][_use_card] +* [Reference API][_reference_api] -* [Get Started][_getstarted_root] documentation - * [Initialize the SDK][_initialize_root] - * [Encrypted storage][_getstarted_storage] - * [Encrypted communication][_getstarted_encryption] - * [Data integrity][_getstarted_data_integrity] - * [Passwordless login][_getstarted_passwordless_login] -* [Guides][_guides] - * [Virgil Cards][_guide_virgil_cards] - * [Virgil Keys][_guide_virgil_keys] -* [Reference API][_reference_api] ## License This library is released under the [3-clause BSD License](LICENSE.md). ## Support - -Our developer support team is here to help you. You can find us on [Twitter](https://twitter.com/virgilsecurity) and [email](support). - -[support]: mailto:support@virgilsecurity.com -[_getstarted_root]: https://developer.virgilsecurity.com/docs/cs/get-started -[_getstarted]: https://developer.virgilsecurity.com/docs/cs/guides -[_getstarted_encryption]: https://developer.virgilsecurity.com/docs/cs/get-started/encrypted-communication -[_getstarted_storage]: https://developer.virgilsecurity.com/docs/cs/get-started/encrypted-storage -[_getstarted_data_integrity]: https://developer.virgilsecurity.com/docs/cs/get-started/data-integrity -[_getstarted_passwordless_login]: https://developer.virgilsecurity.com/docs/cs/get-started/passwordless-authentication -[_guides]: https://developer.virgilsecurity.com/docs/cs/guides -[_guide_initialization]: https://developer.virgilsecurity.com/docs/cs/guides/settings/install-sdk -[_guide_virgil_cards]: https://developer.virgilsecurity.com/docs/cs/guides/virgil-card/creating -[_guide_virgil_keys]: https://developer.virgilsecurity.com/docs/cs/guides/virgil-key/generating -[_guide_encryption]: https://developer.virgilsecurity.com/docs/cs/guides/encryption/encrypting -[_initialize_root]: https://developer.virgilsecurity.com/docs/cs/guides/settings/initialize-sdk-on-client -[_reference_api]: http://virgilsecurity.github.io/virgil-sdk-net/ +Our developer support team is here to help you. + +You can find us on [Twitter](https://twitter.com/VirgilSecurity) or send us email support@VirgilSecurity.com. + +Also, get extra help from our support team on [Slack](https://join.slack.com/t/VirgilSecurity/shared_invite/enQtMjg4MDE4ODM3ODA4LTc2OWQwOTQ3YjNhNTQ0ZjJiZDc2NjkzYjYxNTI0YzhmNTY2ZDliMGJjYWQ5YmZiOGU5ZWEzNmJiMWZhYWVmYTM). + +[_virgil_crypto]: https://github.com/VirgilSecurity/virgil-sdk-crypto-net +[_cards_service]: https://developer.virgilsecurity.com/docs/api-reference/card-service/v5 +[_use_card]: https://developer.virgilsecurity.com/docs/cs/how-to/public-key-management/use-card-for-crypto-operation +[_get_card]: https://developer.virgilsecurity.com/docs/cs/how-to/public-key-management/get-card +[_search_card]: https://developer.virgilsecurity.com/docs/cs/how-to/public-key-management/search-card +[_create_card]: https://developer.virgilsecurity.com/docs/cs/how-to/public-key-management/create-card +[_own_crypto]: https://developer.virgilsecurity.com/docs/cs/how-to/setup/setup-own-crypto-library +[_key_storage]: https://developer.virgilsecurity.com/docs/cs/how-to/setup/setup-key-storage +[_card_verifier]: https://developer.virgilsecurity.com/docs/cs/how-to/setup/setup-card-verifier +[_card_manager]: https://developer.virgilsecurity.com/docs/cs/how-to/setup/setup-card-manager +[_setup_authentication]: https://developer.virgilsecurity.com/docs/cs/how-to/setup/setup-authentication +[_reference_api]: https://developer.virgilsecurity.com/docs/api-reference +[_configure_sdk]: https://developer.virgilsecurity.com/docs/how-to#sdk-configuration +[_more_examples]: https://developer.virgilsecurity.com/docs/how-to#public-key-management diff --git a/SDK/Source/.nuget/NuGet.Config b/SDK/Source/.nuget/NuGet.Config index 67f8ea04..308b678b 100644 --- a/SDK/Source/.nuget/NuGet.Config +++ b/SDK/Source/.nuget/NuGet.Config @@ -1,6 +1,6 @@ - + - \ No newline at end of file + diff --git a/SDK/Source/.nuget/NuGet.targets b/SDK/Source/.nuget/NuGet.targets index 3f8c37b2..4a8b70f0 100644 --- a/SDK/Source/.nuget/NuGet.targets +++ b/SDK/Source/.nuget/NuGet.targets @@ -126,11 +126,9 @@ - + \ No newline at end of file diff --git a/SDK/Source/.vs/config/applicationhost.config b/SDK/Source/.vs/config/applicationhost.config deleted file mode 100644 index a1c32495..00000000 --- a/SDK/Source/.vs/config/applicationhost.config +++ /dev/null @@ -1,1038 +0,0 @@ - - - - - - - - -
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- - -
-
-
-
-
-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SDK/Source/Virgil.CryptoApi/IAccessTokenSigner.cs b/SDK/Source/Virgil.CryptoApi/IAccessTokenSigner.cs new file mode 100644 index 00000000..d4b8d470 --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/IAccessTokenSigner.cs @@ -0,0 +1,72 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.CryptoAPI +{ + /// + /// The provides interface + /// to sign access token and verify its signature using and . + /// + public interface IAccessTokenSigner + { + /// + /// Represents used signature algorithm. + /// + /// + string GetAlgorithm(); + + /// + /// Generates the digital signature for the specified using + /// the specified + /// + /// The material representation bytes of access token + /// for which to compute the signature. + /// The private key + /// The digital signature for the material representation bytes of access token. + byte[] GenerateTokenSignature(byte[] tokenBytes, IPrivateKey privateKey); + + /// + /// Verifies that a digital signature is valid by checking the and + /// provided and . + /// + /// The material representation bytes of access token + /// for which the has been generated. + /// The digital signature for the + /// The public key + /// True if signature is valid, False otherwise. + bool VerifyTokenSignature(byte[] signature, byte[] tokenBytes, IPublicKey publicKey); + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.CryptoApi/ICardCrypto.cs b/SDK/Source/Virgil.CryptoApi/ICardCrypto.cs new file mode 100644 index 00000000..8d1a6bd6 --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/ICardCrypto.cs @@ -0,0 +1,87 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.CryptoAPI +{ + /// + /// The interface defines a list of methods that provide a signature + /// generation and signature verification methods. + /// + public interface ICardCrypto + { + /// + /// Generates the digital signature for the specified using + /// the specified + /// + /// The input data for which to compute the signature. + /// The private key + /// The digital signature for the specified data. + byte[] GenerateSignature(byte[] inputBytes, IPrivateKey privateKey); + + /// + /// Verifies that a digital signature is valid by checking the and + /// provided and . + /// + /// The input data for which the + /// has been generated. + /// The digital signature for the + /// The public key + /// True if signature is valid, False otherwise. + bool VerifySignature(byte[] signature, byte[] inputBytes, IPublicKey publicKey); + + /// + /// Generates the fingerprint(512-bit hash) for the specified . + /// + /// The input data for which to compute the fingerprint. + /// The fingerprint for specified data. + byte[] GenerateSHA512(byte[] inputBytes); + + /// + /// Imports the public key from its material representation. + /// + /// The public key material representation bytes. + /// The instance of imported + /// from . + IPublicKey ImportPublicKey(byte[] publicKeyBytes); + + /// + /// Exports the provided into material representation bytes. + /// + /// The public key + /// The public key material representation bytes. + byte[] ExportPublicKey(IPublicKey publicKey); + } +} diff --git a/SDK/Source/Virgil.SDK.Contracts/Cryptography/IPrivateKey.cs b/SDK/Source/Virgil.CryptoApi/IPrivateKey.cs similarity index 92% rename from SDK/Source/Virgil.SDK.Contracts/Cryptography/IPrivateKey.cs rename to SDK/Source/Virgil.CryptoApi/IPrivateKey.cs index cc1088dd..0b826d68 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Cryptography/IPrivateKey.cs +++ b/SDK/Source/Virgil.CryptoApi/IPrivateKey.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,11 +34,11 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Cryptography +namespace Virgil.CryptoAPI { /// - /// The object represents an opaque reference to keying material - /// that is managed by the agent. + /// The object represents an opaque reference to + /// keying material that is managed by the agent. /// public interface IPrivateKey { diff --git a/SDK/Source/Virgil.CryptoApi/IPrivateKeyExporter.cs b/SDK/Source/Virgil.CryptoApi/IPrivateKeyExporter.cs new file mode 100644 index 00000000..ca58cf8b --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/IPrivateKeyExporter.cs @@ -0,0 +1,64 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + + +namespace Virgil.CryptoAPI +{ + + /// + /// The provides interface + /// to export into its material representation bytes and + /// import from its material representation bytes. + /// + public interface IPrivateKeyExporter + { + /// + /// Exports the provided into material representation bytes. + /// + /// The private key. + /// The private key material representation bytes. + byte[] ExportPrivatekey(IPrivateKey privateKey); + + + /// + /// Imports the private key from its material representation. + /// + /// The private key material representation bytes. + /// The instance of imported + /// from . + IPrivateKey ImportPrivateKey(byte[] privateKeyBytes); + } +} diff --git a/SDK/Source/Virgil.SDK.Contracts/Cryptography/IPublicKey.cs b/SDK/Source/Virgil.CryptoApi/IPublicKey.cs similarity index 92% rename from SDK/Source/Virgil.SDK.Contracts/Cryptography/IPublicKey.cs rename to SDK/Source/Virgil.CryptoApi/IPublicKey.cs index 94956158..62487351 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Cryptography/IPublicKey.cs +++ b/SDK/Source/Virgil.CryptoApi/IPublicKey.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,11 +34,11 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Cryptography +namespace Virgil.CryptoAPI { /// - /// The object represents an opaque reference to keying material - /// that is managed by the agent. + /// The object represents an opaque reference to + /// keying material that is managed by the agent. /// public interface IPublicKey { diff --git a/SDK/Source/Virgil.CryptoApi/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.CryptoApi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..2b266b32 --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Virgil.CryptoAPI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/SDK/Source/Virgil.CryptoApi/Virgil.CryptoAPI.nuspec b/SDK/Source/Virgil.CryptoApi/Virgil.CryptoAPI.nuspec new file mode 100644 index 00000000..8cb0e273 --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/Virgil.CryptoAPI.nuspec @@ -0,0 +1,39 @@ + + + + Virgil.CryptoAPI + $version$ + Virgil.CryptoAPI + Virgil Security, Inc + Virgil Security, Inc + Virgil.CryptoAPI provides the required interfaces to Virgil.SDK. + + + +Virgil Security allows for every developer can build cryptographic features including end-to-end encryption, passwordless authentication, and cryptographic verification of data, devices, and identities into their products, with no cryptographic training. Virgil SDK simplifies their work with Virgil Security services(keys management and identities validation) and Crypto Library(modern algorithms with crypto agility). + +Docs - https://developer.virgilsecurity.com/docs/cs +Source - https://github.com/VirgilSecurity/virgil-sdk-net + +Supported Platforms: + - .NET Framework 4.5+ + - ASP.NET Core 1.0+ + - Windows 8+ + - Windows Phone 8.1+ + - Windows Phone Silverlight 8+ + - Xamarin.Android + - Xamarin.iOS + - Xamarin.iOS (Classic) + + en-US + https://virgilsecurity.com/ + https://avatars0.githubusercontent.com/u/9740508 + false + http://opensource.org/licenses/Apache-2.0 + © 2018 Virgil Security, Inc. + + + + PKI, Cryptography, Cross Platform + + \ No newline at end of file diff --git a/SDK/Source/Virgil.CryptoApi/Virgil.CryptoApi.csproj b/SDK/Source/Virgil.CryptoApi/Virgil.CryptoApi.csproj new file mode 100644 index 00000000..ee41317e --- /dev/null +++ b/SDK/Source/Virgil.CryptoApi/Virgil.CryptoApi.csproj @@ -0,0 +1,39 @@ + + + + Debug + AnyCPU + {BCC9EB08-9768-413E-A69D-FE45699F213D} + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + true + Library + Virgil.CryptoApi + Virgil.CryptoApi + v4.5 + Profile111 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + + + true + bin\Release + prompt + 4 + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryAlreadyExistsException.cs b/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryAlreadyExistsException.cs deleted file mode 100644 index 35913fcc..00000000 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryAlreadyExistsException.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// The exception that is thrown when an key is already exists. - /// - public class KeyEntryAlreadyExistsException : KeyStorageException - { - /// - /// Initializes a new instance of the class. - /// - public KeyEntryAlreadyExistsException() : base("Key with specified name is already exists.") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryNotFoundException.cs b/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryNotFoundException.cs deleted file mode 100644 index ba59dd1b..00000000 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyEntryNotFoundException.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// The exception that is thrown when an key is not found. - /// - public class KeyEntryNotFoundException : KeyStorageException - { - /// - /// Initializes a new instance of the class. - /// - public KeyEntryNotFoundException() : base("Key with specified name is not found.") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/SignatureIsNotValidException.cs b/SDK/Source/Virgil.SDK.Contracts/Exceptions/SignatureIsNotValidException.cs deleted file mode 100644 index 3ace57ab..00000000 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/SignatureIsNotValidException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class SignatureIsNotValidException : CryptoException - { - /// - /// Initializes a new instance of the class. - /// - public SignatureIsNotValidException() : base("Digital signature is not valid") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/VirgilException.cs b/SDK/Source/Virgil.SDK.Contracts/Exceptions/VirgilException.cs deleted file mode 100644 index f9b49523..00000000 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/VirgilException.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - using System; - - /// - /// Represents errors occurred during interaction with SDK components. - /// - public class VirgilException : Exception - { - public VirgilException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Virgil.SDK.Contracts.csproj b/SDK/Source/Virgil.SDK.Contracts/Virgil.SDK.Contracts.csproj index ef2bd3d3..9337882d 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Virgil.SDK.Contracts.csproj +++ b/SDK/Source/Virgil.SDK.Contracts/Virgil.SDK.Contracts.csproj @@ -38,19 +38,7 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Droid/Virgil.SDK.Droid.csproj.bak b/SDK/Source/Virgil.SDK.Droid/Virgil.SDK.Droid.csproj.bak new file mode 100644 index 00000000..3b211df5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Droid/Virgil.SDK.Droid.csproj.bak @@ -0,0 +1,88 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {6B9CE116-871B-4294-AA8E-64DE316AA79A} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Virgil.SDK + Virgil.SDK + 512 + Resources\Resource.Designer.cs + Off + True + v6.0 + + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + ..\packages\Virgil.Crypto.2.2.3\lib\monoandroid\Virgil.Crypto.dll + + + + + + + + + + + + + + + + {bcc9eb08-9768-413e-a69d-fe45699f213d} + Virgil.CryptoApi + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Droid/packages.config b/SDK/Source/Virgil.SDK.Droid/packages.config new file mode 100644 index 00000000..d2dd5600 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Droid/packages.config @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Mac/AppSettings.cs b/SDK/Source/Virgil.SDK.Mac/AppSettings.cs new file mode 100644 index 00000000..6a2a5363 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/AppSettings.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using Newtonsoft.Json; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests +{ + public class AppSettings + { + static AppSettings(){ + var cryptoTestData = File.ReadAllText("TestData/crypto_compatibility_data.json"); + AppSettings.CryptoCompatibilityData = cryptoTestData; + + } + + public static string AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + public static string AccounId = ConfigurationManager.AppSettings["virgil:AccountID"]; + public static string AppPrivateKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; + public static string ApiPublicKeyId = ConfigurationManager.AppSettings["virgil:AccessPublicKeyId"]; + public static string ApiPrivateKeyBase64 = ConfigurationManager.AppSettings["virgil:AccessPrivateKeyBase64"]; + public static string ServiceCardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"]; + public static string ServicePublicKeyPemBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyPemBase64"]; + public static string ServicePublicKeyDerBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"]; + public static string CryptoCompatibilityData = ""; + public static string OutputTestDataPath = ConfigurationManager.AppSettings["test:OutputDataPath"]; + public static string CardsServiceAddress = ConfigurationManager.AppSettings["virgil:CardsServicesAddressV5"]; + + public static string PrivateKeySTC31_1 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_1"]; + public static string PrivateKeySTC31_2 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_2"]; + public static string PublicKeySTC32 = ConfigurationManager.AppSettings["test:PublicKeySTC32"]; + + public static string ImportedAccessPublicKeyId = ConfigurationManager.AppSettings["test:ImportedAccessPublicKeyId"]; + public static string ImportedAccessPublicKey = ConfigurationManager.AppSettings["test:ImportedAccessPublicKey"]; + + public static string PredefinedPrivateKeyBase64 = ConfigurationManager.AppSettings["test:PredefinedPrivateKeyBase64"]; + + public static string ImportedJwt = ConfigurationManager.AppSettings["test:ImportedJwt"]; + } +} diff --git a/SDK/Source/Virgil.SDK.Mac/Exceptions/DuplicateKeyException.cs b/SDK/Source/Virgil.SDK.Mac/Exceptions/DuplicateKeyException.cs new file mode 100644 index 00000000..c9a08be2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/Exceptions/DuplicateKeyException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when an key already exists. + /// + public class DuplicateKeyException : SecureStorageException + { + public DuplicateKeyException(string key) + : base($"Specified key '{key}' is already exists in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Mac/Exceptions/KeyNotFoundException.cs b/SDK/Source/Virgil.SDK.Mac/Exceptions/KeyNotFoundException.cs new file mode 100644 index 00000000..03f6e5fe --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/Exceptions/KeyNotFoundException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when the key doesn't exist. + /// + public class KeyNotFoundException : SecureStorageException + { + public KeyNotFoundException(string key) + : base($"Specified key '{key}' doesn't exist in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Mac/Exceptions/SecureStorageException.cs b/SDK/Source/Virgil.SDK.Mac/Exceptions/SecureStorageException.cs new file mode 100644 index 00000000..c0ba2a49 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/Exceptions/SecureStorageException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Virgil.SDK.Storage.Exceptions +{ + public class SecureStorageException : Exception + { + public SecureStorageException(string message) : base(message) + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Mac/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.SDK.Mac/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e30f3eac --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Virgil.SDK.Mac")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/SDK/Source/Virgil.SDK.Mac/SecureStorage.cs b/SDK/Source/Virgil.SDK.Mac/SecureStorage.cs new file mode 100644 index 00000000..f11dbc5e --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/SecureStorage.cs @@ -0,0 +1,156 @@ +using System; +using Foundation; +using Security; +using Virgil.SDK.Storage; +using Virgil.SDK.Storage.Exceptions; + +namespace Virgil.SDK.Storage +{ + public class SecureStorage + { + /// + /// Storage identity + /// + public static string StorageIdentity = "Virgil.SecureStorage"; + + /// + /// Constructor + /// + public SecureStorage() + { + if (string.IsNullOrWhiteSpace(StorageIdentity)) + { + throw new SecureStorageException("StorageIdentity can't be empty"); + } + } + + /// + /// Stores the key data to the given alias. + /// + /// The alias. + /// The key data. + /// + public void Save(string alias, byte[] data) + { + this.ValidateAlias(alias); + this.ValidateData(data); + + if (this.Exists(alias)) + { + throw new DuplicateKeySecureStorageException(alias); + } + var record = NewSecRecord(alias, data); + var result = SecKeyChain.Add(record); + if (result != SecStatusCode.Success) + { + throw new SecureStorageException($"The key under alias '{alias}' can't be saved."); + }; + } + + /// + /// Checks if the key data exists in this storage by given alias. + /// + /// The alias. + /// true if the key data exists, false otherwise + public bool Exists(string alias) + { + this.ValidateAlias(alias); + + return (this.FindRecord(alias).Item1 == SecStatusCode.Success); + } + + /// + /// Loads the key data associated with the given alias. + /// + /// The alias. + /// + /// The requested data, or exception if the given key does not exist. + /// + /// + public byte[] Load(string alias) + { + this.ValidateAlias(alias); + + var foundSecRecordWithStatus = this.FindRecord(alias); + if (foundSecRecordWithStatus.Item1 == SecStatusCode.Success) + { + return foundSecRecordWithStatus.Item2.ValueData.ToArray(); + } + + throw new KeyNotFoundSecureStorageException(alias); + } + + /// + /// Delete key data by the alias in this storage. + /// + /// The alias. + /// + public void Delete(string alias) + { + this.ValidateAlias(alias); + + var foundSecRecordWithStatus = this.FindRecord(alias); + if (foundSecRecordWithStatus.Item1 != SecStatusCode.Success) + { + throw new KeyNotFoundSecureStorageException(alias); + } + var secRecord = NewSecRecord(alias, null); + SecKeyChain.Remove(secRecord); + } + + /// + /// Returns the list of aliases + /// + public string[] Aliases() + { + // all labels at the Virgil storage + var secRecord = new SecRecord(SecKind.GenericPassword) { Service = StorageIdentity }; + var foundSecRecords = SecKeyChain.QueryAsRecord(secRecord, 100, out var secStatusCode); + var aliases = new string[foundSecRecords.Length]; + + for (var i = 0; i < foundSecRecords.Length; i++) + { + aliases[i] = foundSecRecords[i].Label; + } + return aliases; + } + + private Tuple FindRecord(string alias) + { + var secRecord = NewSecRecord(alias, null); + var found = SecKeyChain.QueryAsRecord(secRecord, out var secStatusCode); + return new Tuple(secStatusCode, found); + } + + private SecRecord NewSecRecord(string alias, byte[] data) + { + var secRecord = new SecRecord(SecKind.GenericPassword) + { + Account = alias, + Service = StorageIdentity, + Label = alias + }; + if (data != null && data.Length > 0) + { + secRecord.ValueData = NSData.FromArray(data); + } + return secRecord; + } + + private void ValidateAlias(string alias) + { + if (string.IsNullOrWhiteSpace(alias)) + { + throw new ArgumentException($"{nameof(alias)} can't be empty."); + } + } + + private void ValidateData(byte[] data) + { + if (data == null || data.Length == 0) + { + throw new ArgumentException($"{nameof(data)} can't be empty."); + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.Mac/Virgil.SDK.Mac.csproj b/SDK/Source/Virgil.SDK.Mac/Virgil.SDK.Mac.csproj new file mode 100644 index 00000000..5c037699 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/Virgil.SDK.Mac.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + {D4FDF98B-0EF0-47E3-ABCF-675CECC0C22D} + {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Virgil.SDK.Mac + Virgil.SDK.Mac + Resources + v2.0 + Xamarin.Mac + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + false + false + false + false + HttpClientHandler + None + + + + true + bin\Release + + prompt + 4 + false + false + false + false + false + HttpClientHandler + None + + + + + + + + + + + ..\packages\Virgil.Crypto.2.2.5\lib\xamarinmac\Virgil.Crypto.dll + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Mac/packages.config b/SDK/Source/Virgil.SDK.Mac/packages.config new file mode 100644 index 00000000..415d80d0 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Mac/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/CardInfoModel.cs b/SDK/Source/Virgil.SDK.NetFx/Exceptions/DuplicateKeyException.cs similarity index 81% rename from SDK/Source/Virgil.SDK.Shared/Client/CardInfoModel.cs rename to SDK/Source/Virgil.SDK.NetFx/Exceptions/DuplicateKeyException.cs index c39cb482..638dec24 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/CardInfoModel.cs +++ b/SDK/Source/Virgil.SDK.NetFx/Exceptions/DuplicateKeyException.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,20 +33,16 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion - -namespace Virgil.SDK.Client +namespace Virgil.SDK.Exceptions { - using Newtonsoft.Json; - /// - /// Represents a transfered object that provide information about device. + /// The exception that is thrown when an key already exists. /// - public class CardInfoModel + public class DuplicateKeyException : SecureStorageException { - [JsonProperty("device")] - public string Device { get; set; } - - [JsonProperty("device_name")] - public string DeviceName { get; set; } + public DuplicateKeyException(string key) + : base($"Specified key '{key}' is already exists in the secure storage.") + { + } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestMetaModel.cs b/SDK/Source/Virgil.SDK.NetFx/Exceptions/KeyNotFoundException.cs similarity index 80% rename from SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestMetaModel.cs rename to SDK/Source/Virgil.SDK.NetFx/Exceptions/KeyNotFoundException.cs index 6b84fc56..55c57298 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestMetaModel.cs +++ b/SDK/Source/Virgil.SDK.NetFx/Exceptions/KeyNotFoundException.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,18 +33,16 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion - -namespace Virgil.SDK.Client +namespace Virgil.SDK.Exceptions { - using System.Collections.Generic; - using Newtonsoft.Json; - - internal class SignableRequestMetaModel + /// + /// The exception that is thrown when the key doesn't exist. + /// + public class KeyNotFoundException : SecureStorageException { - [JsonProperty("signs")] - public Dictionary Signatures { get; set; } - - [JsonProperty("validation")] - public SignableRequestValidationModel Validation { get; set; } + public KeyNotFoundException(string key) + : base($"Specified key '{key}' doesn't exist in the secure storage.") + { + } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityType.cs b/SDK/Source/Virgil.SDK.NetFx/Exceptions/SecureStorageException.cs similarity index 84% rename from SDK/Source/Virgil.SDK.Shared/IdentityType.cs rename to SDK/Source/Virgil.SDK.NetFx/Exceptions/SecureStorageException.cs index 98975060..89aaed24 100644 --- a/SDK/Source/Virgil.SDK.Shared/IdentityType.cs +++ b/SDK/Source/Virgil.SDK.NetFx/Exceptions/SecureStorageException.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,17 +33,14 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion +using System; -namespace Virgil.SDK +namespace Virgil.SDK.Exceptions { - using System.Runtime.Serialization; - - public enum IdentityType + public class SecureStorageException : Exception { - [EnumMember(Value = "application")] - Application, - - [EnumMember(Value = "email")] - Email + public SecureStorageException(string message) : base(message) + { + } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.NetFx/KeyStorageReaderV4.cs b/SDK/Source/Virgil.SDK.NetFx/KeyStorageReaderV4.cs new file mode 100644 index 00000000..c25597fc --- /dev/null +++ b/SDK/Source/Virgil.SDK.NetFx/KeyStorageReaderV4.cs @@ -0,0 +1,154 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Security.Cryptography; +using Newtonsoft.Json; + +namespace Virgil.SDK +{ + public class KeyStorageReaderV4 + { + /// + /// The provides an opportunity to load keys + /// which were saved in previous storage version from SDK v4 + /// + + private readonly string keysPath; + + /// + /// Initializes a new instance of the class. + /// + public KeyStorageReaderV4(string keysFolderPath, bool isAbsolutePath = true) + { + if (isAbsolutePath) + { + this.keysPath = keysFolderPath; + } + else + { + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + this.keysPath = Path.Combine(appData, "VirgilSecurity", keysFolderPath); + } + } + + /// + /// Initializes a new instance of the class. + /// + public KeyStorageReaderV4() + { + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + this.keysPath = Path.Combine(appData, "VirgilSecurity", "Keys"); + } + + + /// + /// Loads the key associated with the given alias from SDK v4 storage. + /// + /// The alias name. + /// + /// + /// The requested key, or null if the given alias does not exist or does + /// not identify a key-related entry. + /// + public Tuple> Load(string keyName) + { + + if (!this.Exists(keyName)) + { + throw new KeyNotFoundException(); + } + + var keyEntryType = new + { + value = new byte[] { }, + meta_data = new Dictionary() + }; + + var encryptedData = File.ReadAllBytes(this.GetKeyPairPath(keyName)); + var data = ProtectedData.Unprotect(encryptedData, null, DataProtectionScope.CurrentUser); + var keyEntryJson = Encoding.UTF8.GetString(data); + + var keyEntryObject = JsonConvert.DeserializeAnonymousType(keyEntryJson, keyEntryType); + + return new Tuple>(keyEntryObject.value, keyEntryObject.meta_data); + + } + + /// + /// Checks if the key associated with the given alias exists in this SDK v4 keystore. + /// + /// The alias name. + public bool Exists(string keyName) + { + return File.Exists(this.GetKeyPairPath(keyName)); + } + + public string[] Names() + { + if (Directory.Exists(this.keysPath)) + { + return Directory.GetFiles(this.keysPath).Select(f => Path.GetFileName(f)).ToArray(); + } + else + { + return new string[] { }; + } + } + + /// + /// Delete the key associated with the given alias from this SDK v4 keystore. + /// + /// The alias name. + /// + public void Delete(string keyName) + { + if (!this.Exists(keyName)) + throw new KeyNotFoundException(); + + File.Delete(this.GetKeyPairPath(keyName)); + } + + private string GetKeyPairPath(string alias) + { + return Path.Combine(this.keysPath, alias.ToLower()); + } + + } +} diff --git a/SDK/Source/Virgil.SDK.NetFx/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.SDK.NetFx/Properties/AssemblyInfo.cs index 13273ce5..795646eb 100644 --- a/SDK/Source/Virgil.SDK.NetFx/Properties/AssemblyInfo.cs +++ b/SDK/Source/Virgil.SDK.NetFx/Properties/AssemblyInfo.cs @@ -2,37 +2,38 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Virgil.SDK")] -[assembly: AssemblyDescription("Virgil SDK enable simplified software development through the use of an intuitive and straightforward Virgil Services. \nhttps://virgilsecurity.com/docs/sdk/net/index\nSupported Platforms:\n- Xamarin(MonoMac, MonoTouch, MonoAndroid, Xamarin.Mac, Xamarin iOS Universal)\n- Portable Libraries(.NET Framework 4+, Silverlight 5.0, Windows 8+)")] +[assembly: AssemblyTitle("Virgil.SDK.NetFx")] +[assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Virgil Security, Inc")] -[assembly: AssemblyProduct("Virgil.SDK")] -[assembly: AssemblyCopyright("© 2016 Virgil Security, Inc.")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Virgil.SDK.NetFx")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +[assembly: InternalsVisibleTo("Virgil.SDK.Tests")] +[assembly: InternalsVisibleTo("Virgil.SDK.Tests.Shared")] + -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -[assembly: InternalsVisibleTo("Virgil.SDK.Tests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("e597b732-df22-4899-b27b-4c47aac4ee3f")] +[assembly: Guid("724be592-c519-4490-9057-f62f3b2fee2c")] // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// 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("4.3.1.0")] -[assembly: AssemblyFileVersion("4.3.1.0")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SDK/Source/Virgil.SDK.NetFx/SecureStorage.cs b/SDK/Source/Virgil.SDK.NetFx/SecureStorage.cs new file mode 100644 index 00000000..b84cd2b0 --- /dev/null +++ b/SDK/Source/Virgil.SDK.NetFx/SecureStorage.cs @@ -0,0 +1,182 @@ +using System; +using System.IO; +using System.IO.IsolatedStorage; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Virgil.SDK.Exceptions; + +namespace Virgil.SDK +{ + + public class SecureStorage + { + /// + /// Storage identity + /// + public static string StorageIdentity = "Virgil.SecureStorage"; + + /// + /// User-scoped isolated storage + /// + private readonly IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForAssembly(); + + /// + /// Password for storage + /// + private byte[] password; + /// + /// Constructor + /// + /// Password for storage + public SecureStorage(string password) + { + + if (string.IsNullOrWhiteSpace(StorageIdentity)) + { + throw new SecureStorageException("StorageIdentity can't be empty"); + } + if (string.IsNullOrWhiteSpace(password)) + { + throw new SecureStorageException("Password can't be empty"); + } + this.password = Encoding.UTF8.GetBytes(password); + } + + /// + /// Stores the key data to the given alias. + /// + /// The alias. + /// The key data. + /// + public void Save(string alias, byte[] data) + { + this.ValidateAlias(alias); + + this.ValidateData(data); + + if (this.Exists(alias)) + { + throw new DuplicateKeyException(alias); + } + var encryptedData = ProtectedData.Protect(data, this.password, DataProtectionScope.CurrentUser); + + if (!this.appStorage.DirectoryExists(StorageIdentity)) + { + this.appStorage.CreateDirectory(StorageIdentity); + } + + try + { + // save encrypted bytes to file + using (var stream = this.appStorage.CreateFile(this.FilePath(alias))) + { + stream.Write(encryptedData, 0, encryptedData.Length); + stream.Close(); + } + } + catch (Exception) + { + throw new SecureStorageException($"The key under alias '{alias}' can't be saved."); + } + } + + /// + /// Checks if the key data exists in this storage by given alias. + /// + /// The alias. + /// true if the key data exists, false otherwise + public bool Exists(string alias) + { + this.ValidateAlias(alias); + + return this.appStorage.FileExists(this.FilePath(alias)); + } + + /// + /// Loads the key data associated with the given alias. + /// + /// The alias. + /// + /// The requested data, or exception if the given key does not exist. + /// + /// + public byte[] Load(string alias) + { + this.ValidateAlias(alias); + + if (this.Exists(alias)) + { + using (var stream = this.appStorage.OpenFile(this.FilePath(alias), + FileMode.Open, + FileAccess.ReadWrite)) + { + // allocate and read the protected data + var protectedData = new byte[stream.Length]; + stream.Read(protectedData, 0, (int)stream.Length); + + try + { + // obtain clear data by decrypting + return ProtectedData.Unprotect(protectedData, this.password, + DataProtectionScope.CurrentUser); + } + catch (CryptographicException) + { + throw new SecureStorageException("Wrong password."); + } + } + } + throw new KeyNotFoundException(alias); + } + + /// + /// Delete key data by the alias in this storage. + /// + /// The alias. + /// + public void Delete(string alias) + { + this.ValidateAlias(alias); + + if (!this.Exists(alias)) + { + throw new KeyNotFoundException(alias); + } + this.appStorage.DeleteFile(this.FilePath(alias)); + } + + /// + /// Returns the list of aliases that are kept in the storage. + /// + public string[] Aliases() + { + //all filenames at the root of app storage + var fileNames = this.appStorage.GetFileNames($"{StorageIdentity}\\*"); + //all keys + return fileNames.Select(x => Encoding.UTF8.GetString(Convert.FromBase64String(x))).ToArray(); + } + + private string FilePath(string key) + { + var keyBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(key)); + return $"{StorageIdentity}\\{keyBase64}"; + } + + private void ValidateAlias(string alias) + { + if (string.IsNullOrWhiteSpace(alias)) + { + throw new ArgumentException($"{nameof(alias)} can't be empty."); + } + } + + private void ValidateData(byte[] data) + { + if (data == null || data.Length == 0) + { + throw new ArgumentException($"{nameof(data)} can't be empty."); + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.csproj b/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.csproj index df9e6681..e94af352 100644 --- a/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.csproj +++ b/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.csproj @@ -1,10 +1,10 @@  - + Debug AnyCPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F} + {724BE592-C519-4490-9057-F62F3B2FEE2C} Library Properties Virgil.SDK @@ -13,6 +13,7 @@ 512 + true @@ -24,7 +25,8 @@ 4 - pdbonly + + true bin\Release\ TRACE @@ -32,12 +34,12 @@ 4 - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + @@ -46,40 +48,20 @@ - - ..\packages\Virgil.Crypto.2.1.2\lib\portable-net4+sl4+wp7+win8+wpa81\Virgil.Crypto.dll - True - - - ..\packages\Virgil.SDK.Contracts.1.1.2.0\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Virgil.SDK.Contracts.dll - True + + ..\packages\Virgil.CryptoAPI.1.0.0\lib\portable-net45+win+wpa81+MonoTouch10+xamarinmac20\Virgil.CryptoApi.dll - + + + + + - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.nuspec b/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.nuspec deleted file mode 100644 index 8436d338..00000000 --- a/SDK/Source/Virgil.SDK.NetFx/Virgil.SDK.NetFx.nuspec +++ /dev/null @@ -1,33 +0,0 @@ - - - - Virgil.SDK - $version$ - Virgil.SDK - Virgil Security, Inc - Virgil Security, Inc - With Virgil Security every developer can build cryptographic features including end-to-end encryption, passwordless authentication, and cryptographic verification of data, devices, and identities into their products, with no cryptographic training. Virgil SDK simplifies their work with Virgil Security services(keys management and identities validation) and Crypto Library(modern algorithms with crypto agility). - - - -With Virgil Security every developer can build cryptographic features including end-to-end encryption, passwordless authentication, and cryptographic verification of data, devices, and identities into their products, with no cryptographic training. Virgil SDK simplifies their work with Virgil Security services(keys management and identities validation) and Crypto Library(modern algorithms with crypto agility). - -Docs - https://virgilsecurity.com/docs/sdk/net/v4.0(latest)/dot-net-csharp-sdk -Source - https://github.com/VirgilSecurity/virgil-sdk-net - -Supported Platforms: - - .NET Framework 4.5+ - - Windows 8+ - - en-US - https://virgilsecurity.com/ - https://avatars0.githubusercontent.com/u/9740508 - false - http://opensource.org/licenses/Apache-2.0 - © 2016 Virgil Security, Inc. - - - - PKI, Cryptography, Crossplatform - - \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.NetFx/VirgilApiContext.cs b/SDK/Source/Virgil.SDK.NetFx/VirgilApiContext.cs deleted file mode 100644 index ddcc9c42..00000000 --- a/SDK/Source/Virgil.SDK.NetFx/VirgilApiContext.cs +++ /dev/null @@ -1,58 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using Virgil.SDK.Device; - using Virgil.SDK.Storage; - - /// - /// The class manages the dependencies during run time. - /// It also contains a list of preperties that uses to configurate the high-level components. - /// - public partial class VirgilApiContext - { - private IKeyStorage GetDefaultKeyStorage() - { - return new DefaultKeyStorage(); - } - - private IDeviceManager GetDefaultDeviceManager() - { - return new DeviceManager(); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.NetFx/VirgilBuffer.cs b/SDK/Source/Virgil.SDK.NetFx/VirgilBuffer.cs deleted file mode 100644 index 5e3ccd53..00000000 --- a/SDK/Source/Virgil.SDK.NetFx/VirgilBuffer.cs +++ /dev/null @@ -1,58 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System.IO; - - /// - /// The class provides a list of methods that - /// simplify the work with an array of bytes. - /// - public partial class VirgilBuffer - { - /// - /// Initializes a new buffer from specified file, reads the contents of the - /// file into . - /// - /// A new instance of class. - public static VirgilBuffer FromFile(string filePath) - { - var fileBytes = File.ReadAllBytes(filePath); - return new VirgilBuffer(fileBytes); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.NetFx/packages.config b/SDK/Source/Virgil.SDK.NetFx/packages.config index 522b4a97..3d0bea68 100644 --- a/SDK/Source/Virgil.SDK.NetFx/packages.config +++ b/SDK/Source/Virgil.SDK.NetFx/packages.config @@ -1,6 +1,5 @@  - - - + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/AppCredentials.cs b/SDK/Source/Virgil.SDK.Shared/AppCredentials.cs deleted file mode 100644 index 2fde6732..00000000 --- a/SDK/Source/Virgil.SDK.Shared/AppCredentials.cs +++ /dev/null @@ -1,82 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using Virgil.SDK.Cryptography; - - /// - /// Provides credentials for application authentication using AppID and AppKey - /// retrieved from development deshboard. - /// - public class AppCredentials : Credentials - { - /// - /// Gets or sets the application ID that uniquely identifies your application in our services, - /// and it is also used to identify the Virgil Card/Public key generated in a pair with . - /// - public string AppId { get; set; } - - /// - /// Gets or sets the application key that is representing a Private key that is used to perform - /// creation and revocation of Virgil Cards (Public key) in Virgil services. Also the can - /// be used for cryptographic operations to take part in application logic. - /// - public VirgilBuffer AppKey { get; set; } - - /// - /// Gets or sets the application key password that is used to protect the . - /// - public string AppKeyPassword { get; set; } - - /// - /// Gets the application used to authenticate Publish/Revoke Card requests. - /// - public override IPrivateKey GetAppKey(ICrypto crypto) - { - var authorityPrivateKey = crypto.ImportPrivateKey(this.AppKey.GetBytes(), this.AppKeyPassword); - return authorityPrivateKey; - } - - /// - /// Gets the application identifier. - /// - public override string GetAppId() - { - return this.AppId; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Card.cs b/SDK/Source/Virgil.SDK.Shared/Card.cs new file mode 100644 index 00000000..e6ffd0db --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Card.cs @@ -0,0 +1,133 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.SDK +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Virgil.CryptoAPI; + + using Virgil.SDK.Common; + using Virgil.SDK.Web; + + /// + /// The class is the main entity of Virgil Services. Every user/device is + /// represented with a Virgil Card which contains a public key and information about identity. + /// + public class Card + { + private List signatures; + + private Card() + { + } + + internal Card( + string cardId, + string identity, + IPublicKey publicKey, + string version, + DateTime createdAt, + List signautes, + string previousCardId, + byte[] contentSnapshot, + bool isOutDated = false + ) + { + this.Id = cardId; + this.Identity = identity; + this.PublicKey = publicKey; + this.Version = version; + this.CreatedAt = createdAt; + this.signatures = signautes; + this.PreviousCardId = previousCardId; + this.ContentSnapshot = contentSnapshot; + this.IsOutdated = isOutDated; + } + + /// + /// Gets the Card ID that uniquely identifies the Card in Virgil Services. + /// + public string Id { get; private set; } + + /// + /// Gets the identity value that can be anything which identifies the user in your application. + /// + public string Identity { get; private set; } + + /// + /// Gets the public key. + /// + public IPublicKey PublicKey { get; private set; } + + /// + /// Gets the version of the card. + /// + public string Version { get; private set; } + + /// + /// Gets the date and time fo card creation in UTC. + /// + public DateTime CreatedAt { get; private set; } + + /// + /// Get previous Card ID that current card is used to override to. + /// + public string PreviousCardId { get; private set; } + + /// + /// Get previous Card that current card is used to override to. + /// + public Card PreviousCard { get; internal set; } + + /// + /// Get the snapshot of . + /// + public byte[] ContentSnapshot { get; private set; } + + /// + /// Whether the card is overridden by another card. + /// + public bool IsOutdated { get; internal set; } + + /// + /// Gets a list of signatures. + /// + public IReadOnlyList Signatures => this.signatures; + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/CardManager.cs b/SDK/Source/Virgil.SDK.Shared/CardManager.cs new file mode 100644 index 00000000..bce15168 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/CardManager.cs @@ -0,0 +1,412 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using Virgil.SDK.Signer; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK +{ + using System.Threading.Tasks; + using Virgil.CryptoAPI; + using Virgil.SDK.Common; + using Verification; + using Virgil.SDK.Web; + + /// + /// The provides operations with Virgil Cards. + /// + public class CardManager + { + /// + /// an instance of which provides cryptographic operations. + /// + public readonly ICardCrypto CardCrypto; + + + public readonly ModelSigner ModelSigner; + + public ICardClient Client { get; internal set; } + + /// + /// an instance of which provides card verification. + /// + public readonly ICardVerifier CardVerifier; + + /// + /// CallBack which performs additional signatures for card before publishing. + /// + public readonly Func> SignCallBack; + + /// + /// an instance of which provides token delivery. + /// + public readonly IAccessTokenProvider AccessTokenProvider; + + /// + /// If true repeats once a request to the after + /// getting . + /// + public readonly bool RetryOnUnauthorized; + + /// + /// Initializes a new instance of the class by + /// a specified set of parameters. + /// + /// the instance of . + public CardManager(CardManagerParams @params) + { + ValidateCardManagerParams(@params); + this.CardCrypto = @params.CardCrypto; + this.AccessTokenProvider = @params.AccessTokenProvider; + this.Client = string.IsNullOrWhiteSpace(@params.ApiUrl) + ? new CardClient() + : new CardClient(@params.ApiUrl); + + this.CardVerifier = @params.Verifier; + this.ModelSigner = new ModelSigner(CardCrypto); + this.SignCallBack = @params.SignCallBack; + this.RetryOnUnauthorized = @params.RetryOnUnauthorized; + } + + + private static void ValidateCardManagerParams(CardManagerParams @params) + { + if (@params.CardCrypto == null) + { + throw new ArgumentException($"{nameof(@params.CardCrypto)} property is mandatory"); + } + + if (@params.AccessTokenProvider == null) + { + throw new ArgumentException($"{nameof(@params.AccessTokenProvider)} property is mandatory"); + } + } + + /// + /// Gets the card by specified ID. + /// + /// The card ID to be found. + /// The instance of found . + public async Task GetCardAsync(string cardId) + { + if (String.IsNullOrWhiteSpace(cardId)) + { + throw new ArgumentException(nameof(cardId)); + } + var tokenContext = new TokenContext(null, "get"); + var accessToken = await AccessTokenProvider.GetTokenAsync(tokenContext); + + var cardWithStatus = (Tuple)await TryExecute( + async (IAccessToken token) => + { + return await this.Client.GetCardAsync(cardId, + token.ToString()); + }, tokenContext, accessToken); + var card = CardUtils.Parse(this.CardCrypto, (RawSignedModel)cardWithStatus.Item1, cardWithStatus.Item2); + + if (card.Id != cardId) + { + throw new CardVerificationException("Invalid card"); + } + this.ValidateCards(new Card[] { card }); + + return card; + } + + /// + /// Searches for cards by specified identity. + /// + /// The identity to be found. + /// The list of found . + public async Task> SearchCardsAsync(string identity) + { + if (String.IsNullOrWhiteSpace(identity)) + { + throw new ArgumentException(nameof(identity)); + } + var tokenContext = new TokenContext(null, "search"); + var accessToken = await AccessTokenProvider.GetTokenAsync(tokenContext); + var rawCards = await TryExecute( + async (IAccessToken token) => + { + return await Client.SearchCardsAsync(identity, + token.ToString() + ); + }, tokenContext, accessToken); + + var cards = CardUtils.Parse(this.CardCrypto, (IEnumerable)rawCards).ToArray(); + if (cards.Any(x => x.Identity != identity)) + { + throw new CardVerificationException("Invalid cards"); + } + this.ValidateCards(cards); + return CardUtils.LinkedCardLists(cards); + } + + /// + /// Publish a new Card using specified . + /// + /// The instance of class. + /// It should has mandatory parameters: public key, private key + /// The instance of newly published class. + public async Task PublishCardAsync(CardParams cardParams) + { + ValidateCardParams(cardParams); + + var tokenContext = new TokenContext(cardParams.Identity, "publish"); + + var token = await this.AccessTokenProvider.GetTokenAsync(tokenContext); + var rawSignedModel = GenerateRawCard(new CardParams() + { + Identity = token.Identity(), + PrivateKey = cardParams.PrivateKey, + PublicKey = cardParams.PublicKey, + PreviousCardId = cardParams.PreviousCardId, + ExtraFields = cardParams.ExtraFields + }); + + return await PublishRawSignedModel(rawSignedModel, tokenContext, token); + } + + private async Task PublishRawSignedModel(RawSignedModel rawSignedModel, + TokenContext context, + IAccessToken accessToken) + { + if (this.SignCallBack != null) + { + rawSignedModel = await this.SignCallBack.Invoke(rawSignedModel); + } + + var publishedModel = await TryExecute( + async (IAccessToken token) => + { + var rawCard = await Client.PublishCardAsync( + rawSignedModel, + token.ToString() + ); + return rawCard; + }, context, accessToken); + + if (!rawSignedModel.ContentSnapshot.SequenceEqual(((RawSignedModel)publishedModel).ContentSnapshot)) + { + throw new CardVerificationException("Publishing returns invalid card"); + } + var card = CardUtils.Parse(this.CardCrypto, (RawSignedModel)publishedModel); + this.ValidateCards(new[] { card }); + + return card; + } + + private async Task TryExecute(Func> func, TokenContext context, IAccessToken token) + { + object result = null; + // if RetryOnUnauthorized == true then add one attempt + var attemptsNumber = (RetryOnUnauthorized ? 2 : 1); + for (var i = 0; i < attemptsNumber; i++) + { + try + { + result = await func.Invoke(token); + break; + } + catch (UnauthorizedClientException e) + { + if (i == attemptsNumber - 1) + { + throw e; + } + + token = await this.AccessTokenProvider.GetTokenAsync( + new TokenContext(context.Identity, context.Operation, true) + ); + } + } + return result; + } + + /// + /// Generates a new in order to apply for a card registration. + /// + /// The instance of class. + /// It should has mandatory parameters: identity, public key, private key + /// A new self signed instance of class. + public RawSignedModel GenerateRawCard(CardParams cardParams) + { + ValidateCardParams(cardParams, true); + var timeNow = DateTime.UtcNow; + //to truncate milliseconds and microseconds + timeNow = timeNow.AddTicks(-timeNow.Ticks % TimeSpan.TicksPerSecond); + var model = RawSignedModelUtils.Generate(CardCrypto, cardParams, timeNow); + ModelSigner.SelfSign(model, cardParams.PrivateKey, cardParams.ExtraFields); + return model; + } + + private static void ValidateCardParams(CardParams cardParams, bool validateIdentity = false) + { + if (cardParams == null) + { + throw new ArgumentNullException(nameof(cardParams)); + } + if (validateIdentity && String.IsNullOrWhiteSpace(cardParams.Identity)) + { + throw new ArgumentException($"{nameof(cardParams.Identity)} property is mandatory"); + } + if (cardParams.PublicKey == null) + { + throw new ArgumentException($"{nameof(cardParams.PublicKey)} property is mandatory"); + } + + if (cardParams.PrivateKey == null) + { + throw new ArgumentException($"{nameof(cardParams.PrivateKey)} property is mandatory"); + } + } + + /// + /// Publish a new Card using specified . + /// + /// The instance of class. + /// The instance of newly published class. + public async Task PublishCardAsync(RawSignedModel rawSignedModel) + { + var cardContent = SnapshotUtils.ParseSnapshot( + rawSignedModel.ContentSnapshot); + var tokenContext = new TokenContext(cardContent.Identity, "publish"); + + var token = await this.AccessTokenProvider.GetTokenAsync(tokenContext); + + return await PublishRawSignedModel(rawSignedModel, tokenContext, token); + } + + /// + /// Exports the specified card as a BASE64 string. + /// + /// the instance of to be exported. + /// serialized card to BASE64. + /// Use this method to transmit the card + /// signing request through the network. + public string ExportCardAsString(Card card) + { + return ExportCardAsRawCard(card).ExportAsString(); + } + + /// + /// Exports the specified card as a json. + /// + /// the instance of to be exported. + /// serialized card to JSON. + /// Use this method to transmit the card + /// signing request through the network. + public string ExportCardAsJson(Card card) + { + return ExportCardAsRawCard(card).ExportAsJson(); + } + + /// + /// Exports card as an instance of . + /// + /// the instance of to be exported. + /// an instance of representing Card. + public RawSignedModel ExportCardAsRawCard(Card card) + { + return RawSignedModelUtils.Parse(CardCrypto, card); + } + + /// + /// Imports and verifies from json. + /// + /// json to get card from. + /// Imported and verified card. + public Card ImportCardFromJson(string json) + { + var rawSignedModel = RawSignedModelUtils.GenerateFromJson(json); + var card = CardUtils.Parse(CardCrypto, rawSignedModel); + this.ValidateCards(new[] { card }); + return card; + } + + /// + /// Imports and verifies from an + /// instance of . + /// + /// an instance of + /// to get card from. + /// Imported and verified card. + public Card ImportCard(RawSignedModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + var card = CardUtils.Parse(CardCrypto, model); + this.ValidateCards(new[] { card }); + return card; + } + + /// + /// Imports and verifies from BASE64 string. + /// + /// BASE64 string to get card from. + /// Imported and verified card. + public Card ImportCardFromString(string str) + { + var rawSignedModel = RawSignedModelUtils.GenerateFromString(str); + var card = CardUtils.Parse(CardCrypto, rawSignedModel); + this.ValidateCards(new[] { card }); + return card; + } + + private void ValidateCards(Card[] cards) + { + if (this.CardVerifier == null) + { + return; + } + + foreach (var card in cards) + { + var result = this.CardVerifier.VerifyCard(card); + if (!result) + { + throw new CardVerificationException("Validation errors have been detected"); + } + } + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/SearchCriteria.cs b/SDK/Source/Virgil.SDK.Shared/CardManagerParams.cs similarity index 55% rename from SDK/Source/Virgil.SDK.Shared/Client/SearchCriteria.cs rename to SDK/Source/Virgil.SDK.Shared/CardManagerParams.cs index e9cc275c..6248fa41 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/SearchCriteria.cs +++ b/SDK/Source/Virgil.SDK.Shared/CardManagerParams.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,57 +33,54 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion - -namespace Virgil.SDK.Client + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using Virgil.SDK.Web; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK { - using System.Collections.Generic; + using Virgil.CryptoAPI; + using Verification; /// - /// The search criteria that determines what cards list to retrieve. + /// The contains parameters + /// required for initializing /// - public class SearchCriteria + public class CardManagerParams { /// - /// Gets or sets the identities. + /// an instance of which provides cryptographic operations. /// - public IEnumerable Identities { get; set; } + public ICardCrypto CardCrypto { get; set; } /// - /// Gets or sets the type of the identity. + /// an instance of which provides card verification. /// - public string IdentityType { get; set; } + public ICardVerifier Verifier { get; set; } /// - /// Gets or sets the scope. + /// CallBack which performs additional signatures for card before publishing. /// - public CardScope Scope { get; set; } + public Func> SignCallBack { get; set; } - public static SearchCriteria ByIdentities(params string[] identities) - { - return new SearchCriteria - { - Identities = identities, - Scope = CardScope.Application - }; - } + /// + /// + /// + public string ApiUrl { get; set; } - public static SearchCriteria ByIdentity(string identity) - { - return new SearchCriteria - { - Identities = new[] { identity }, - Scope = CardScope.Application - }; - } + /// + /// an instance of which provides token delivery. + /// + public IAccessTokenProvider AccessTokenProvider { get; set; } - public static SearchCriteria ByAppBundle(string bundle) - { - return new SearchCriteria - { - Identities = new[] { bundle }, - IdentityType = "application", - Scope = CardScope.Global - }; - } + /// + /// If true repeats once a request to the after + /// getting . + /// + public bool RetryOnUnauthorized { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/CardParams.cs b/SDK/Source/Virgil.SDK.Shared/CardParams.cs new file mode 100644 index 00000000..bbac8b0a --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/CardParams.cs @@ -0,0 +1,75 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System.Collections.Generic; + +namespace Virgil.SDK +{ + using Virgil.CryptoAPI; + + /// + /// The combines key parameters required by + /// for creating Virgil Card instance on the Virgil Cards Service. + /// + public class CardParams + { + /// + /// Gets or sets a unique identity value. + /// + public string Identity { get; set; } + + /// + /// Gets or sets a public key. + /// + public IPublicKey PublicKey { get; set; } + + /// + /// Gets or sets a private key. Used to generate self signature. + /// + public IPrivateKey PrivateKey { get; set; } + + /// + /// Gets or sets previous card id that current card is used to override to. + /// + public string PreviousCardId { get; set; } + + /// + /// Gets or sets the additional data associated with the card. + /// + public Dictionary ExtraFields { get; set; } + + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Device/IDeviceManager.cs b/SDK/Source/Virgil.SDK.Shared/CardSignature.cs similarity index 73% rename from SDK/Source/Virgil.SDK.Contracts/Device/IDeviceManager.cs rename to SDK/Source/Virgil.SDK.Shared/CardSignature.cs index 6496f1e4..8e24eab9 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Device/IDeviceManager.cs +++ b/SDK/Source/Virgil.SDK.Shared/CardSignature.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,32 +34,33 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Device +namespace Virgil.SDK { + using System.Collections.Generic; + /// - /// The provides an information about the device such as assigned name, - /// device model, and operating-system name and version. + /// provides signature for . /// - public interface IDeviceManager + public class CardSignature { /// - /// Gets the name of the current device. + /// Gets the type of signer signature. /// - string GetDeviceName(); + public string Signer { get; internal set; } /// - /// Gets the name of the operating system running on the device represented by the receiver. + /// Get the generated digital signature. /// - string GetSystemName(); + public byte[] Signature { get; internal set; } /// - /// Gets the current version of the operating system. + /// Get the signature snapshot. /// - string GetSystemVersion(); + public byte[] Snapshot { get; internal set; } /// - /// Gets the model of the device. + /// Get the custom fields associated with the signature. /// - string GetDeviceModel(); + public IReadOnlyDictionary ExtraFields { get; internal set; } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/CardsManager.cs b/SDK/Source/Virgil.SDK.Shared/CardsManager.cs deleted file mode 100644 index 96684753..00000000 --- a/SDK/Source/Virgil.SDK.Shared/CardsManager.cs +++ /dev/null @@ -1,338 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using Exceptions; - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - - using Virgil.SDK.Client; - using Virgil.SDK.Common; - - /// - /// The class provides a list of methods to manage the entities. - /// - internal class CardsManager : ICardsManager - { - private readonly VirgilApiContext context; - - /// - /// Initializes a new instance of the class. - /// - public CardsManager(VirgilApiContext context) - { - this.context = context; - } - - /// - /// Creates a new that is representing user's Public key and information - /// about identity. This card has to be published to the Virgil's services. - /// - /// The user's identity. - /// Type of the identity. - /// The owner's . - /// The custom fields (optional). - /// A new instance of class, that is unpublished and - /// representing user's Public key. - public VirgilCard Create(string identity, VirgilKey ownerKey, - string identityType = "unknown", - Dictionary customFields = null) - { - var cardModel = this.BuildCardModel(identity, identityType, customFields, - CardScope.Application, ownerKey); - - return new VirgilCard(this.context, cardModel); - } - - /// - /// Creates a new global that is representing user's - /// Public key and information about identity. - /// - /// The user's identity value. - /// Type of the identity. - /// The owner's . - /// The custom fields (optional). - /// A new instance of class, that is representing user's Public key. - public VirgilCard CreateGlobal(string identity, IdentityType identityType, VirgilKey ownerKey, - Dictionary customFields = null) - { - var identityTypeString = Enum.GetName(typeof(IdentityType), identityType)?.ToLower(); - - var cardModel = this.BuildCardModel(identity, identityTypeString, customFields, - CardScope.Global, ownerKey); - - return new VirgilCard(this.context, cardModel); - } - - /// - /// Finds a s by specified identities in application scope. - /// - /// The list of identities. - /// A collection of found s. - public async Task> FindAsync(params string[] identities) - { - if (identities == null || identities.Length == 0) - throw new ArgumentNullException(nameof(identities)); - - return await this.FindAsync(null, identities); - } - - /// - /// Finds s by specified identities and type in application scope. - /// - /// Type of identity - /// The list of sought identities - /// A new collection with found s. - public async Task> FindAsync(string identityType, IEnumerable identities) - { - var identityList = identities as IList ?? identities.ToList(); - - if (identities == null || !identityList.Any()) - throw new ArgumentNullException(nameof(identities)); - - var criteria = new SearchCriteria - { - Identities = identityList, - IdentityType = identityType, - Scope = CardScope.Application - }; - - var cards = await this.SearchByCriteriaAsync(criteria).ConfigureAwait(false); - return cards; - } - - /// - /// Finds s by specified identities and type in global scope. - /// - /// The list of sought identities - /// A new collection with found s. - public async Task> FindGlobalAsync(params string[] identities) - { - var identityList = identities as IList ?? identities.ToList(); - - if (identities == null || !identityList.Any()) - throw new ArgumentNullException(nameof(identities)); - - var criteria = new SearchCriteria - { - Identities = identityList, - Scope = CardScope.Global - }; - - var cards = await this.SearchByCriteriaAsync(criteria).ConfigureAwait(false); - return cards; - } - - /// - /// Finds s by specified identities and type in global scope. - /// - /// Type of identity - /// The list of sought identities - /// A new collection with found s. - public async Task> FindGlobalAsync(IdentityType identityType, params string[] identities) - { - var identityList = identities as IList ?? identities.ToList(); - - if (identities == null || !identityList.Any()) - throw new ArgumentNullException(nameof(identities)); - - var criteria = new SearchCriteria - { - Identities = identityList, - IdentityType = Enum.GetName(typeof(IdentityType), identityType)?.ToLower(), - Scope = CardScope.Global - }; - - var cards = await this.SearchByCriteriaAsync(criteria).ConfigureAwait(false); - return cards; - } - - /// - /// Imports a from specified buffer. - /// - /// A Card in string representation. - /// An instance of . - public VirgilCard Import(string exportedCard) - { - var bufferCard = VirgilBuffer.From(exportedCard, StringEncoding.Base64); - var importedCardModel = JsonSerializer.Deserialize(bufferCard.ToString()); - - return new VirgilCard(this.context, importedCardModel); - } - - /// - /// Publishes a into global Virgil Services scope. - /// - /// The Card to be published. - /// The identity validation token. - public Task PublishGlobalAsync(VirgilCard card, IdentityValidationToken token) - { - return card.PublishAsGlobalAsync(token); - } - - /// - /// Publishes a into application Virgil Services scope. - /// - /// The Card to be published. - public Task PublishAsync(VirgilCard card) - { - return card.PublishAsync(); - } - - /// - /// Revokes a from Virgil Services. - /// - /// The card to be revoked. - public async Task RevokeAsync(VirgilCard card) - { - if ((this.context == null) || (this.context.Credentials == null) || - (this.context.Credentials.GetAppId() == null) || - (this.context.Credentials.GetAppKey(context.Crypto) == null)) - { - throw new AppCredentialsException(); - } - var revokeRequest = new RevokeCardRequest(card.Id, RevocationReason.Unspecified); - - var appId = this.context.Credentials.GetAppId(); - var appKey = this.context.Credentials.GetAppKey(this.context.Crypto); - - - var fingerprint = this.context.Crypto.CalculateFingerprint(revokeRequest.Snapshot); - var signature = this.context.Crypto.Sign(fingerprint.GetValue(), appKey); - - revokeRequest.AppendSignature(appId, signature); - - /* to_ask - var requestSigner = new RequestSigner(this.context.Crypto); - requestSigner.AuthoritySign(revokeRequest, appId, appKey); */ - - await this.context.Client.RevokeCardAsync(revokeRequest); - } - - /// - /// Revokes a global from Virgil Security services. - /// - /// The Card to be revoked. - /// The Key associated with the revoking Card. - /// The identity token. - public async Task RevokeGlobalAsync(VirgilCard card, VirgilKey key, IdentityValidationToken identityToken) - { - var revokeRequest = new RevokeGlobalCardRequest(card.Id, RevocationReason.Unspecified, identityToken.Value); - - var fingerprint = this.context.Crypto.CalculateFingerprint(revokeRequest.Snapshot); - var signature = key.Sign(fingerprint.GetValue()); - - revokeRequest.AppendSignature(card.Id, signature.GetBytes()); - - /* to_ask - var requestSigner = new RequestSigner(this.context.Crypto); - requestSigner.AuthoritySign(revokeRequest, card.Id, key.PrivateKey); - */ - - await this.context.Client.RevokeGlobalCardAsync(revokeRequest); - } - - /// - /// Gets a from Virgil Security services by specified Card ID. - /// - /// is a unique string that identifies the Card - /// within Virgil Security services. - /// an instance of class. - public async Task GetAsync(string cardId) - { - var cardModel = await this.context.Client.GetCardAsync(cardId).ConfigureAwait(false); - var card = new VirgilCard(this.context, cardModel); - - return card; - } - - private async Task> SearchByCriteriaAsync(SearchCriteria criteria) - { - var cardModels = await this.context.Client.SearchCardsAsync(criteria).ConfigureAwait(false); - return cardModels.Select(model => new VirgilCard(this.context, model)).ToList(); - } - - private CardModel BuildCardModel - ( - string identity, - string identityType, - Dictionary customFields, - CardScope scope, - VirgilKey ownerKey - ) - { - var cardSnapshotModel = new PublishCardSnapshotModel - { - Identity = identity, - IdentityType = identityType, - Info = new CardInfoModel - { - DeviceName = this.context.DeviceManager.GetDeviceName(), - Device = this.context.DeviceManager.GetSystemName() - }, - PublicKeyData = ownerKey.ExportPublicKey().GetBytes(), - Scope = scope, - Data = customFields - }; - - var snapshot = new Snapshotter().Capture(cardSnapshotModel); - - var snapshotFingerprint = this.context.Crypto.CalculateFingerprint(snapshot); - var cardId = snapshotFingerprint.ToHEX(); - var selfSignature = ownerKey.Sign(VirgilBuffer.From(snapshotFingerprint.GetValue())); - - var signatures = new Dictionary - { - [cardId] = selfSignature.GetBytes() - }; - - var cardModel = new CardModel(cardSnapshotModel) - { - Id = cardId, - Snapshot = snapshot, - Meta = new CardMetaModel - { - Signatures = signatures - } - }; - - return cardModel; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/CardModel.cs b/SDK/Source/Virgil.SDK.Shared/Client/CardModel.cs deleted file mode 100644 index 3a593781..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/CardModel.cs +++ /dev/null @@ -1,90 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System.Text; - using Newtonsoft.Json; - - /// - /// The class represents an information about Virgil Card entity. - /// - public class CardModel - { - private PublishCardSnapshotModel snapshotModel; - - /// - /// Initializes a new instance of the class. - /// - public CardModel() - { - } - - /// - /// Initializes a new instance of the class. - /// - internal CardModel(PublishCardSnapshotModel model) - { - this.snapshotModel = model; - } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("content_snapshot")] - public byte[] Snapshot { get; set; } - - [JsonIgnore] - public PublishCardSnapshotModel SnapshotModel - { - get - { - if (this.snapshotModel != null || this.Snapshot == null) - { - return this.snapshotModel; - } - - var snapshotModelJson = Encoding.UTF8.GetString(this.Snapshot); - this.snapshotModel = Common.JsonSerializer.Deserialize(snapshotModelJson); - - return this.snapshotModel; - } - } - - [JsonProperty("meta")] - public CardMetaModel Meta { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/DeleteRelationRequest.cs b/SDK/Source/Virgil.SDK.Shared/Client/DeleteRelationRequest.cs deleted file mode 100644 index 49352a09..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/DeleteRelationRequest.cs +++ /dev/null @@ -1,51 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - public class DeleteRelationRequest : RevokeCardRequest - { - /// - /// Initializes a new instance of the class. - /// - /// The card ID to be revoked. - /// The revocation reason. - public DeleteRelationRequest(string cardId, RevocationReason reason) : base(cardId, reason) - { - } - } -} - diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/CardsServiceConnection.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/CardsServiceConnection.cs deleted file mode 100644 index 282dd26b..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/CardsServiceConnection.cs +++ /dev/null @@ -1,187 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client.Http -{ - using System; - using System.Collections.Generic; - using System.Net.Http; - - using Virgil.SDK.Exceptions; - - /// - /// A connection for making HTTP requests against URI endpoints for public api services. - /// - /// - /// - internal class CardsServiceConnection : ConnectionBase, IConnection - { - /// - /// Initializes a new instance of the class. - /// - /// Application token - /// The base address. - public CardsServiceConnection(string accessToken, Uri baseAddress) : base(accessToken, baseAddress) - { - this.Errors = new Dictionary - { - [10000] = "Internal application error. You know, shit happens, so do internal server errors.Just take a deep breath and try harder.", - [20300] = "The Virgil access token was not specified or is invalid", - [20301] = "The Virgil authenticator service responded with an error", - [20302] = "The Virgil access token validation has failed on the Virgil Authenticator service", - [20303] = "The application was not found for the acsses token", - [20400] = "Request sign is invalid", - [20401] = "Request sign header is missing", - [20500] = "The Virgil Card is not available in this application", - [30000] = "JSON specified as a request is invalid", - [30010] = "A data inconsistency error", - [30100] = "Global Virgil Card identity type is invalid, because it can be only an 'email'", - [30101] = "Virgil Card scope must be either 'global' or 'application'", - [30102] = "Virgil Card id validation failed", - [30103] = "Virgil Card data parameter cannot contain more than 16 entries", - [30104] = "Virgil Card info parameter cannot be empty if specified and must contain 'device' and/or 'device_name' key", - [30105] = "Virgil Card info parameters length validation failed.The length cannot exceed 256 characters", - [30106] = "Virgil Card data parameter must be an associative array(https://en.wikipedia.org/wiki/Associative_array)", - [30107] = "A CSR parameter (content_snapshot) parameter is missing or is incorrect", - [30111] = "Virgil Card identities passed to search endpoint must be a list of non-empty strings", - [30113] = "Virgil Card identity type is invalid", - [30114] = "Segregated Virgil Card custom identity value must be a not empty string", - [30115] = "Virgil Card identity email is invalid", - [30116] = "Virgil Card identity application is invalid", - [30117] = "Public key length is invalid.It goes from 16 to 2048 bytes", - [30118] = "Public key must be base64-encoded string", - [30119] = "Virgil Card data parameter must be a key/value list of strings", - [30120] = "Virgil Card data parameters must be strings", - [30121] = "Virgil Card custom data entry value length validation failed.It mustn't exceed 256 characters", - [30122] = "Identity validation token is invalid", - [30123] = "SCR signs list parameter is missing or is invalid", - [30126] = "SCR sign item signer card id is irrelevant and doesn't match Virgil Card id or Application Id", - [30127] = "SCR sign item signed digest is invalid for the Virgil Card public key", - [30128] = "SCR sign item signed digest is invalid for the application", - [30131] = "Virgil Card id specified in the request body must match with the one passed in the URL", - [30134] = "Virgil Card data parameters key must be aplphanumerical", - [30135] = "Virgil Card validation token must be an object with value parameter", - [30136] = "SCR sign item signed digest is invalid for the virgil identity service", - [30137] = "Global Virigl Card cannot be created unconfirmed(which means that Virgil Identity service sign is mandatory)", - [30138] = "Virigl Card with the same fingerprint exists already", - [30139] = "Virigl Card revocation reason isn't specified or is invalid", - [30140] = "SCR sign validation failed", - [30141] = "SCR one of signers Virgil Cards is not found", - [30142] = "SCR sign item is invalid or missing for the Client", - [30143] = "SCR sign item is invalid or missing for the Virgil Registration Authority service", - [30200] = "Virgil Card relation sign is invalid", - [30201] = "Virgil Card relation sign by the source Virgil Card was not found", - [30202] = "Related Virgil content snapshot parameter was not found", - [30203] = "The relation with this Virgil Card exists already", - [30204] = "The related Virgil Card was not found for the provided CSR", - [30205] = "The Virgil Card relation doesn't exist" - }; - } - - /// - /// Handles public keys service exception responses - /// - /// The http response message. - protected override void ExceptionHandler(HttpResponseMessage message) - { - this.ThrowException(message, (code, msg) => new VirgilClientException(code, msg)); - } - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/ConnectionBase.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/ConnectionBase.cs deleted file mode 100644 index 36ab7b97..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/ConnectionBase.cs +++ /dev/null @@ -1,210 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; - using System.Net.Http; - using System.Text; - using System.Threading.Tasks; - using Exceptions; - using Newtonsoft.Json; - - /// - /// - internal abstract class ConnectionBase : IConnection - { - /// - /// The error code to message mapping dictionary - /// - protected Dictionary Errors = new Dictionary(); - - /// - /// The access token header name - /// - protected const string AccessTokenHeaderName = "Authorization"; - - /// - /// Initializes a new instance of the class. - /// - /// The application token. - /// The base address. - protected ConnectionBase(string accessToken, Uri baseAddress) - { - this.AccessToken = accessToken; - this.BaseAddress = baseAddress; - } - - /// - /// Access Token - /// - public string AccessToken { get; protected set; } - - /// - /// Base address for the connection. - /// - public Uri BaseAddress { get; protected set; } - - /// - /// Sends an HTTP request to the API. - /// - /// The HTTP request details. - /// if set to true ignore error. - /// Response - public virtual async Task Send(IRequest request, bool ignoreError = false) - { - using (var httpClient = new HttpClient()) - { - var nativeRequest = this.GetNativeRequest(request); - var nativeResponse = await httpClient.SendAsync(nativeRequest).ConfigureAwait(false); - - if (!ignoreError && !nativeResponse.IsSuccessStatusCode) - { - this.ExceptionHandler(nativeResponse); - } - - var content = nativeResponse.Content.ReadAsStringAsync().Result; - - var response = new Response - { - Body = content, - Headers = nativeResponse.Headers.ToDictionary(it => it.Key, it => it.Value.FirstOrDefault()), - StatusCode = (int) nativeResponse.StatusCode - }; - - return response; - } - } - - /// - /// Produces native HTTP request. - /// - /// The request. - /// HttpRequestMessage - protected virtual HttpRequestMessage GetNativeRequest(IRequest request) - { - var message = new HttpRequestMessage(request.Method.GetMethod(), new Uri(this.BaseAddress, request.Endpoint)); - - if (request.Headers != null) - { - if (this.AccessToken != null) - { - message.Headers.TryAddWithoutValidation(AccessTokenHeaderName, $"VIRGIL {this.AccessToken}" ); - } - - foreach (var header in request.Headers) - { - message.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - } - - if (request.Method != RequestMethod.Get) - { - message.Content = new StringContent(request.Body, Encoding.UTF8, "application/json"); - } - - return message; - } - - /// - /// Handles exception responses - /// - /// The http response message. - protected virtual void ExceptionHandler(HttpResponseMessage message) - { - this.ThrowException(message, (code, msg) => new VirgilServiceException(code, msg)); - } - - /// - /// Parses service response to retrieve error code - /// - /// Http body of service response - /// Parsed error code - protected int TryParseErrorCode(string content) - { - int errorCode; - - try - { - var errorResult = JsonConvert.DeserializeAnonymousType(content, new - { - code = 0 - }); - - errorCode = errorResult.code; - } - catch (JsonException) - { - try - { - var errorResult = JsonConvert.DeserializeAnonymousType(content, new - { - error = new - { - code = 0 - } - }); - - errorCode = errorResult.error.code; - - } - catch - { - errorCode = 0; - } - } - catch - { - errorCode = 0; - } - - return errorCode; - } - - /// - /// Parses service http response and throws apropriate exception - /// - /// Message received from service - /// Exception factory - /// Virgil exception child class - protected void ThrowException(HttpResponseMessage message, Func exception) where T : VirgilServiceException - { - int errorCode = this.TryParseErrorCode(message.Content.ReadAsStringAsync().Result); - string errorMessage; - - if (this.Errors.TryGetValue(errorCode, out errorMessage)) - throw exception(errorCode, errorMessage); - - if (errorCode == 0) - { - switch (message.StatusCode) - { - case HttpStatusCode.BadRequest: - errorMessage = "Request error"; - break; - case HttpStatusCode.Unauthorized: - errorMessage = "Authorization error"; - break; - case HttpStatusCode.NotFound: - errorMessage = "Entity not found"; - break; - case HttpStatusCode.MethodNotAllowed: - errorMessage = "Method not allowed"; - break; - case HttpStatusCode.InternalServerError: - errorMessage = "Internal Server error"; - break; - default: - errorMessage = $"Undefined exception: {errorCode}; Http status: {message.StatusCode}"; - break; - } - } - else - { - errorMessage = $"Undefined exception: {errorCode}; Http status: {message.StatusCode}"; - } - - throw exception(errorCode, errorMessage); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/Extensions.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/Extensions.cs deleted file mode 100644 index 91740071..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/Extensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System; - using System.Net.Http; - - internal static class Extensions - { - internal static HttpMethod GetMethod(this RequestMethod requestMethod) - { - switch (requestMethod) - { - case RequestMethod.Get: return HttpMethod.Get; - case RequestMethod.Post: return HttpMethod.Post; - case RequestMethod.Put: return HttpMethod.Put; - case RequestMethod.Delete: return HttpMethod.Delete; - default: - throw new ArgumentOutOfRangeException(nameof(requestMethod)); - } - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/IConnection.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/IConnection.cs deleted file mode 100644 index 3ecd858c..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/IConnection.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System; - using System.Threading.Tasks; - - /// - /// A connection for making HTTP requests against URI endpoints. - /// - internal interface IConnection - { - /// - /// Base address for the connection. - /// - Uri BaseAddress { get; } - - /// - /// Sends an HTTP request to the API. - /// - /// The HTTP request details. - /// if set to true [ignore error]. - /// - Task Send(IRequest request, bool ignoreError = false); - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/IRequest.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/IRequest.cs deleted file mode 100644 index 3dfcd948..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/IRequest.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System.Collections.Generic; - - /// - /// Represent a generic HTTP request - /// - internal interface IRequest - { - /// - /// Gets the endpoint. Does not include server base address - /// - string Endpoint { get; } - - /// - /// Gets the request method. - /// - RequestMethod Method { get; } - - /// - /// Gets the http headers. - /// - IDictionary Headers { get; } - - /// - /// Gets the requests body. - /// - string Body { get; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/IResponse.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/IResponse.cs deleted file mode 100644 index be9e8bc7..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/IResponse.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System.Collections.Generic; - - /// - /// Represents a generic HTTP response - /// - internal interface IResponse - { - /// - /// Raw response body. - /// - string Body { get; } - - /// - /// Information about the API. - /// - IReadOnlyDictionary Headers { get; } - - /// - /// The response status code. - /// - int StatusCode { get; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/IdentityServiceConnection.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/IdentityServiceConnection.cs deleted file mode 100644 index c823d4af..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/IdentityServiceConnection.cs +++ /dev/null @@ -1,92 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System; - using System.Collections.Generic; - using System.Net.Http; - using Exceptions; - - using Virgil.SDK.Client.Http; - - /// - /// A connection for making HTTP requests against URI endpoints for identity api services. - /// - /// - /// - internal class IdentityServiceConnection : ConnectionBase, IConnection - { - /// - /// Initializes a new instance of the class. - /// - /// Application access token - /// The base address. - public IdentityServiceConnection(string accessToken, Uri baseAddress) : base(accessToken, baseAddress) - { - this.Errors = new Dictionary - { - [10000] = "Internal application error", - [40000] = "JSON specified as a request body is invalid", - [40100] = "Identity type is invalid", - [40110] = "Identity's ttl is invalid", - [40120] = "Identity's ctl is invalid", - [40130] = "Identity's token parameter is missing", - [40140] = "Identity's token doesn't match parameters", - [40150] = "Identity's token has expired", - [40160] = "Identity's token cannot be decrypted", - [40170] = "Identity's token parameter is invalid", - [40180] = "Identity is not unconfirmed", - [40190] = "Hash to be signed parameter is invalid", - [40200] = "Email identity value validation failed", - [40210] = "Identity's confirmation code is invalid", - [40300] = "Application value is invalid", - [40310] = "Application's signed message is invalid", - [41000] = "Identity entity was not found", - [41010] = "Identity's confirmation period has expired" - }; - } - - /// - /// Handles exception responses - /// - /// The http response message. - protected override void ExceptionHandler(HttpResponseMessage message) - { - this.ThrowException(message, (code, msg) => new IdentityServiceServiceException(code, msg)); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/RAServiceConnection.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/RAServiceConnection.cs deleted file mode 100644 index e050dddd..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/RAServiceConnection.cs +++ /dev/null @@ -1,78 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client.Http -{ - using System; - using System.Collections.Generic; - using System.Net.Http; - - using Virgil.SDK.Exceptions; - - /// - /// A connection for making HTTP requests against URI endpoints for RA api service. - /// - /// - /// - internal class RAServiceConnection : ConnectionBase, IConnection - { - /// - /// Initializes a new instance of the class. - /// - /// Application token - /// The base address. - public RAServiceConnection(string accessToken, Uri baseAddress) : base(accessToken, baseAddress) - { - this.Errors = new Dictionary - { - [30300] = "Development Portal signature was not found inside the meta.signs property", - [30301] = "Development Portal signature is invalid", - [30302] = "Development Portal Virgil Card was not found on Cards service", - [30303] = "Identity Validation Token is invalid or has expired", - [30304] = "Provided Virgil Card was not found or invalid" - }; - } - - /// - /// Handles public keys service exception responses - /// - /// The http response message. - protected override void ExceptionHandler(HttpResponseMessage message) - { - this.ThrowException(message, (code, msg) => new VirgilClientException(code, msg)); - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/Request.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/Request.cs deleted file mode 100644 index f3e773d6..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/Request.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System.Collections.Generic; - - /// - /// default implementation"/> - /// - /// - internal class Request : IRequest - { - /// - /// Initializes a new instance of the class. - /// - public Request() - { - this.Headers = new Dictionary(); - } - - /// - /// Gets the endpoint. Does not include server base address - /// - public string Endpoint { get; set; } - - /// - /// Gets the requests body. - /// - public string Body { get; set; } - - /// - /// Gets the http headers. - /// - public IDictionary Headers { get; set; } - - /// - /// Gets the request method. - /// - public RequestMethod Method { get; set; } - - internal static Request Create(RequestMethod method) - { - return new Request {Method = method}; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestExtensions.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestExtensions.cs deleted file mode 100644 index 9146f3c5..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using Virgil.SDK.Common; - - /// - /// Extensions to help construct http requests - /// - internal static class RequestExtensions - { - /// - /// Sets the request enpoint - /// - /// The request. - /// The endpoint. - /// - public static Request WithEndpoint(this Request request, string endpoint) - { - request.Endpoint = endpoint; - return request; - } - - /// - /// Withes the body. - /// - /// The request. - /// The body. - /// - public static Request WithBody(this Request request, object body) - { - request.Body = JsonSerializer.Serialize(body); - return request; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestMethod.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestMethod.cs deleted file mode 100644 index 2de7bde6..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/RequestMethod.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - /// - /// Represents HTTP request methods - /// - internal enum RequestMethod - { - Get, - Post, - Put, - Delete - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/Response.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/Response.cs deleted file mode 100644 index abd37a70..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/Response.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using System.Collections.Generic; - - /// - /// default implementation - /// - internal class Response : IResponse - { - /// - /// Raw response body. - /// - public string Body { get; set; } - - /// - /// Information about the API. - /// - public IReadOnlyDictionary Headers { get; set; } - - /// - /// The response status code. - /// - public int StatusCode { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/Http/ResponseExtensions.cs b/SDK/Source/Virgil.SDK.Shared/Client/Http/ResponseExtensions.cs deleted file mode 100644 index a798e598..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/Http/ResponseExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Virgil.SDK.Client.Http -{ - using Newtonsoft.Json; - - internal static class ResponseExtensions - { - public static TResult Parse(this IResponse response) - { - return JsonConvert.DeserializeObject(response.Body); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/ICardValidator.cs b/SDK/Source/Virgil.SDK.Shared/Client/ICardValidator.cs deleted file mode 100644 index b5a5389d..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/ICardValidator.cs +++ /dev/null @@ -1,50 +0,0 @@ -#region Copyright (C) 2016 Virgil Security Inc. -// Copyright (C) 2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - /// - /// Provides a mechanism for card validation. - /// - public interface ICardValidator - { - /// - /// Validates the specified instance. - /// - /// The card. - bool Validate(CardModel card); - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/PublishCardRequest.cs b/SDK/Source/Virgil.SDK.Shared/Client/PublishCardRequest.cs deleted file mode 100644 index 5a71eada..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/PublishCardRequest.cs +++ /dev/null @@ -1,92 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System.Collections.Generic; - - /// - /// Represents a signable request that uses to publish new to the Virgil Services. - /// - public class PublishCardRequest : SignableRequest - { - /// - /// Initializes a new instance of the class by specified - /// snapshot and signatures. - /// - /// The snapshot of the card request. - /// The signatures. - internal PublishCardRequest(byte[] snapshot, IDictionary signatures) - { - this.takenSnapshot = snapshot; - this.acceptedSignatures = new Dictionary(signatures); - } - - /// - /// Initializes a new instance of the class. - /// - /// The stringified request. - public PublishCardRequest(string stringifiedRequest) : base(stringifiedRequest) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The identity. - /// Type of the identity. - /// The public key data. - /// The information. - /// The custom fields. - public PublishCardRequest( - string identity, - string identityType, - byte[] publicKeyData, - CardInfoModel info = null, - Dictionary customFields = null) - : base(new PublishCardSnapshotModel - { - Identity = identity, - IdentityType = identityType, - PublicKeyData = publicKeyData, - Data = customFields, - Info = info, - Scope = CardScope.Application - }) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/PublishCardSnapshotModel.cs b/SDK/Source/Virgil.SDK.Shared/Client/PublishCardSnapshotModel.cs deleted file mode 100644 index 07727f25..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/PublishCardSnapshotModel.cs +++ /dev/null @@ -1,65 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System.Collections.Generic; - using Newtonsoft.Json; - - /// - /// This class is representing a snapshot model for . - /// - public class PublishCardSnapshotModel - { - [JsonProperty("identity")] - public string Identity { get; set; } - - [JsonProperty("identity_type")] - public string IdentityType { get; set; } - - [JsonProperty("public_key")] - public byte[] PublicKeyData { get; set; } - - [JsonProperty("scope")] - public CardScope Scope { get; set; } - - [JsonProperty("data")] - public Dictionary Data { get; set; } - - [JsonProperty("info")] - public CardInfoModel Info { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/PublishGlobalCardRequest.cs b/SDK/Source/Virgil.SDK.Shared/Client/PublishGlobalCardRequest.cs deleted file mode 100644 index 0995417f..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/PublishGlobalCardRequest.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Virgil.SDK.Client -{ - using System.Collections.Generic; - - /// - /// Represents a signable request that uses to publish new Card to the Virgil Services. - /// - public class PublishGlobalCardRequest : SignableRequest - { - /// - /// Initializes a new instance of the class. - /// - /// The snapshot. - /// The identity validation token. - /// The signatures. - internal PublishGlobalCardRequest(byte[] snapshot, string validationToken, IDictionary signatures) - { - this.takenSnapshot = snapshot; - this.acceptedSignatures = new Dictionary(signatures); - this.validationToken = validationToken; - } - - /// - /// Initializes a new instance of the class. - /// - /// The stringified request. - public PublishGlobalCardRequest(string stringifiedRequest) : base(stringifiedRequest) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The identity. - /// Type of the identity. - /// The public key data. - /// The identity validation token. - /// The information. - /// The custom fields. - public PublishGlobalCardRequest( - string identity, - string identityType, - byte[] publicKeyData, - string validationToken, - CardInfoModel info = null, - Dictionary customFields = null) - : base(new PublishCardSnapshotModel - { - Identity = identity, - IdentityType = identityType, - PublicKeyData = publicKeyData, - Data = customFields, - Info = info, - Scope = CardScope.Global - }) - { - this.validationToken = validationToken; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/RevocationReason.cs b/SDK/Source/Virgil.SDK.Shared/Client/RevocationReason.cs deleted file mode 100644 index c28e2304..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/RevocationReason.cs +++ /dev/null @@ -1,49 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System.Runtime.Serialization; - - public enum RevocationReason - { - [EnumMember(Value = "unspecified")] - Unspecified, - - [EnumMember(Value = "compromised")] - Compromised - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/RevokeCardSnapshotModel.cs b/SDK/Source/Virgil.SDK.Shared/Client/RevokeCardSnapshotModel.cs deleted file mode 100644 index 7f4e07b6..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/RevokeCardSnapshotModel.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region Copyright (C) 2016 Virgil Security Inc. -// Copyright (C) 2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using Newtonsoft.Json; - - public class RevokeCardSnapshotModel - { - /// - /// Gets or sets the card identifier. - /// - [JsonProperty("card_id")] - public string CardId { get; set; } - - /// - /// Gets or sets the reason. - /// - [JsonProperty("revocation_reason")] - public RevocationReason Reason { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/SignableRequest.cs b/SDK/Source/Virgil.SDK.Shared/Client/SignableRequest.cs deleted file mode 100644 index 8734660c..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/SignableRequest.cs +++ /dev/null @@ -1,138 +0,0 @@ -namespace Virgil.SDK.Client -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - - using Virgil.SDK.Common; - - /// - /// - /// - /// The type of the request model. - public abstract class SignableRequest : ISignableRequest - { - protected Dictionary acceptedSignatures; - protected byte[] takenSnapshot; - protected TSnapshotModel snapshotModel; - protected string validationToken; - - /// - /// Initializes a new instance of the class. - /// - protected internal SignableRequest() - { - } - - /// - /// Initializes a new instance of the class. - /// - protected internal SignableRequest(string stringifiedRequest) - { - this.ImportRequest(stringifiedRequest); - } - - /// - /// Initializes a new instance of the class. - /// - protected internal SignableRequest(TSnapshotModel snapshotModel) - { - this.acceptedSignatures = new Dictionary(); - this.snapshotModel = snapshotModel; - } - - /// - /// Gets the snapshot value, that has been taken from request model. - /// - public byte[] Snapshot => this.takenSnapshot ?? (this.takenSnapshot = this.TakeSnapshot()); - - /// - /// Gets the signatures that represents a dictionary of signers Fingerprint as keys and - /// request snapshot Signature as values. - /// - public IReadOnlyDictionary Signatures => this.acceptedSignatures; - - /// - /// Appends the Signature of request snapshot Fingerprint. - /// - public void AppendSignature(string cardId, byte[] signature) - { - if (string.IsNullOrWhiteSpace(cardId)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(cardId)); - - if (signature == null) - throw new ArgumentNullException(nameof(signature)); - - this.acceptedSignatures.Add(cardId, signature); - } - - /// - /// Gets the request model. - /// - internal SignableRequestModel GetRequestModel() - { - var requestModel = new SignableRequestModel - { - ContentSnapshot = this.Snapshot, - Meta = new SignableRequestMetaModel - { - Signatures = this.Signatures.ToDictionary(it => it.Key, it => it.Value) - } - }; - - if (!string.IsNullOrEmpty(this.validationToken)) - { - requestModel.Meta.Validation = new SignableRequestValidationModel - { - Token = this.validationToken - }; - } - - return requestModel; - } - - /// - /// Extracts the request snapshot model from actual snapshotModel. - /// - public TSnapshotModel ExtractSnapshotModel() - { - var jsonSnapshot = Encoding.UTF8.GetString(this.Snapshot); - return JsonSerializer.Deserialize(jsonSnapshot); - } - - /// - /// Exports this request into its string representation. - /// - public string Export() - { - var requestModel = this.GetRequestModel(); - - var json = JsonSerializer.Serialize(requestModel); - var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); - - return base64; - } - - protected void ImportRequest(string exportedRequest) - { - var jsonRequestModel = Encoding.UTF8.GetString(Convert.FromBase64String(exportedRequest)); - var requestModel = JsonSerializer.Deserialize(jsonRequestModel); - - this.takenSnapshot = requestModel.ContentSnapshot; - this.acceptedSignatures = requestModel.Meta.Signatures; - this.validationToken = requestModel.Meta?.Validation?.Token; - } - - private byte[] TakeSnapshot() - { - if (this.takenSnapshot != null) - { - return this.takenSnapshot; - } - - this.takenSnapshot = new Snapshotter().Capture(this.snapshotModel); - return this.takenSnapshot; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityConfirmationResponse.cs b/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityConfirmationResponse.cs deleted file mode 100644 index 1eb76bc1..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityConfirmationResponse.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Virgil.SDK.Shared.Client.TransferObjects -{ - using Newtonsoft.Json; - - /// - /// Represents an confirmed identity information. - /// - internal class IdentityConfirmationResponseModel - { - /// - /// Gets or sets the value. - /// - [JsonProperty("value")] - public string Value { get; set; } - - /// - /// Gets or sets the type. - /// - [JsonProperty("type")] - public IdentityType Type { get; set; } - - /// - /// Gets or sets the validation token. - /// - [JsonProperty("validation_token")] - public string ValidationToken { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityVerificationResponseModel.cs b/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityVerificationResponseModel.cs deleted file mode 100644 index eb30b6d5..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/IdentityVerificationResponseModel.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Virgil.SDK.Shared.Client.TransferObjects -{ - using System; - using Newtonsoft.Json; - - /// - /// Represents virgil verify response - /// - internal class IdentityVerificationResponseModel - { - /// - /// Gets or sets the action identifier. - /// - [JsonProperty("action_id")] - public Guid ActionId { get; set; } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/ValidationOptions.cs b/SDK/Source/Virgil.SDK.Shared/Client/ValidationOptions.cs deleted file mode 100644 index 8bb16244..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/ValidationOptions.cs +++ /dev/null @@ -1,60 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System.Collections.Generic; - - public class ValidationOptions - { - /// - /// The parameter is used to limit the lifetime of the token in seconds - /// (maximum value is 60 * 60 * 24 * 365 = 1 year) - /// - public int TokenTimeToLive { get; set; } - - /// - /// The parameter is used to restrict the number of token - /// usages (maximum value is 100) - /// - public int TokenCountToLive { get; set; } - - /// - /// Gets or sets the extra fields. - /// - public IDictionary ExtraFields { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/VirgilClient.cs b/SDK/Source/Virgil.SDK.Shared/Client/VirgilClient.cs deleted file mode 100644 index 0fa56752..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/VirgilClient.cs +++ /dev/null @@ -1,530 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Shared.Client.TransferObjects; - - using Http; - using Exceptions; - - public sealed class VirgilClient - { - private readonly VirgilClientParams parameters; - - private readonly Lazy cardsConnection; - private readonly Lazy readCardsConnection; - private readonly Lazy identityConnection; - private readonly Lazy raConnection; - - private IConnection CardsConnection => this.cardsConnection.Value; - private IConnection ReadCardsConnection => this.readCardsConnection.Value; - private IConnection IdentityConnection => this.identityConnection.Value; - private IConnection RAConnection => this.raConnection.Value; - - private ICardValidator cardValidator; - - /// - /// Initializes a new instance of the class. - /// - public VirgilClient() : this(new VirgilClientParams()) - { - } - - /// - /// Initializes a new instance of the class. - /// - public VirgilClient(string accessToken) : this(new VirgilClientParams(accessToken)) - { - } - - /// - /// Initializes a new instance of the class. - /// - public VirgilClient(VirgilClientParams parameters) - { - this.parameters = parameters; - - this.cardsConnection = new Lazy(this.InitializeCardsConnection); - this.readCardsConnection = new Lazy(this.InitializeReadCardsConnection); - this.identityConnection = new Lazy(this.InitializeIdentityConnection); - this.raConnection = new Lazy(this.InitializeRAConnection); - } - - /// - /// Sets the card validator. - /// - public void SetCardValidator(ICardValidator validator) - { - if (validator == null) - throw new ArgumentNullException(nameof(validator)); - - this.cardValidator = validator; - } - - - /// Searches cards by specified search criteria. - /// An instance of class - /// Found cards from server response. - /// - /// if client has validator - /// and cards are not valid. - /// - /// - /// var client = new VirgilClient("[YOUR_ACCESS_TOKEN_HERE]"); - /// var foundCardModels = await client.SearchCardsAsync(new SearchCriteria - /// { - /// Identities = new[] { "Bob", "Alice" } - /// }); - /// - /// - public async Task> SearchCardsAsync(SearchCriteria criteria) - { - if (criteria == null) - throw new ArgumentNullException(nameof(criteria)); - - if (criteria.Identities == null || !criteria.Identities.Any()) - throw new ArgumentNullException(nameof(criteria)); - - var body = new Dictionary - { - ["identities"] = criteria.Identities - }; - - if (!string.IsNullOrWhiteSpace(criteria.IdentityType)) - { - body["identity_type"] = criteria.IdentityType; - } - - if (criteria.Scope == CardScope.Global) - { - body["scope"] = "global"; - } - - var request = Request.Create(RequestMethod.Post) - .WithEndpoint("/v4/card/actions/search") - .WithBody(body); - - var response = await this.ReadCardsConnection.Send(request).ConfigureAwait(false); - var cards = response.Parse>().ToList(); - - if (this.cardValidator != null) - { - this.ValidateCards(cards); - } - - return cards; - } - - - /// - /// Publishes card in Virgil Cards service. - /// - /// An instance of class - /// Card that is published to Virgil Security services - /// - /// - /// var crypto = new VirgilCrypto(); - /// var client = new VirgilClient("[YOUR_ACCESS_TOKEN_HERE]"); - /// var appKey = crypto.ImportPrivateKey( - /// File.ReadAllBytes("[YOUR_APP_KEY_PATH_HERE]"), - /// "[YOUR_APP_KEY_PASSWORD_HERE]" - /// ); - /// var aliceKeys = crypto.GenerateKeys(); - /// var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - /// var aliceIdentity = "alice"; - /// var request = new PublishCardRequest(aliceIdentity, "unknown", exportedPublicKey); - /// var requestSigner = new RequestSigner(crypto); - /// requestSigner.SelfSign(request, aliceKeys.PrivateKey); - /// requestSigner.AuthoritySign(request, "[YOUR_APP_ID_HERE]", appKey); - /// var aliceCardModel = await client.PublishCardAsync(request); - /// - /// - public async Task PublishCardAsync(PublishCardRequest request) - { - var postRequest = Request.Create(RequestMethod.Post) - .WithEndpoint("/v4/card") - .WithBody(request.GetRequestModel()); - - var response = await this.CardsConnection.Send(postRequest).ConfigureAwait(false); - var cardModel = response.Parse(); - - if (this.cardValidator != null) - { - this.ValidateCards(new []{ cardModel }); - } - - return cardModel; - } - - - - /// Publishes Global card in Virgil cards service. - /// An instance of class - /// Global card that is published to Virgil Security services. - /// - /// var crypto = new VirgilCrypto(); - /// var client = new VirgilClient(); - /// var aliceKeys = crypto.GenerateKeys(); - /// var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - /// var aliceIdentity = "alice"; - /// var request = new PublishGlobalCardRequest(aliceIdentity, - /// "email", - /// exportedPublicKey, - /// "[YOUR_VALIDATION_TOKEN]" - /// ); - /// var requestSigner = new RequestSigner(crypto); - /// requestSigner.SelfSign(request, aliceKeys.PrivateKey); - /// var aliceGlobalCardModel = await client.PublishGlobalCardAsync(request); - /// - public async Task PublishGlobalCardAsync(PublishGlobalCardRequest request) - { - var postRequest = Request.Create(RequestMethod.Post) - .WithEndpoint("/v1/card") - .WithBody(request.GetRequestModel()); - - var response = await this.RAConnection.Send(postRequest).ConfigureAwait(false); - var cardModel = response.Parse(); - - if (this.cardValidator != null) - { - this.ValidateCards(new[] { cardModel }); - } - return cardModel; - } - - - - /// - /// Revoke Global card by id. - /// - /// An instance of class - /// that contains Global Card id and Validation Token - /// - /// - /// var client = new VirgilClient(); - /// var crypto = new VirgilCrypto(); - /// var revokeRequest = new RevokeGlobalCardRequest(aliceGlobalCard.Id, - /// RevocationReason.Unspecified, - /// "[YOUR_VALIDATION_TOKEN]" - /// ); - /// var requestSigner = new RequestSigner(crypto); - /// requestSigner.AuthoritySign(revokeRequest, aliceGlobalCardModel.Id, aliceKeys.PrivateKey); - /// await client.RevokeGlobalCardAsync(revokeRequest); - /// - /// How to get aliceGlobalCardModel and aliceKeys - /// - /// - public async Task RevokeGlobalCardAsync(RevokeGlobalCardRequest request) - { - var snapshotModel = request.ExtractSnapshotModel(); - var requestModel = request.GetRequestModel(); - - var postRequest = Request.Create(RequestMethod.Delete) - .WithEndpoint($"/v1/card/{snapshotModel.CardId}") - .WithBody(requestModel); - - await this.RAConnection.Send(postRequest).ConfigureAwait(false); - } - - /// - /// Revoke a card from Virgil Services. - /// - /// An instance of class that - /// contains card id - /// - /// - /// var crypto = new VirgilCrypto(); - /// var client = new VirgilClient("[YOUR_ACCESS_TOKEN_HERE]"); - /// var appKey = crypto.ImportPrivateKey( - /// File.ReadAllBytes("[YOUR_APP_KEY_PATH_HERE]"), - /// "[YOUR_APP_KEY_PASSWORD_HERE]" - /// ); - /// var requestSigner = new RequestSigner(crypto); - /// var revokeRequest = new RevokeCardRequest(aliceCardModel.Id, RevocationReason.Unspecified); - /// requestSigner.AuthoritySign(revokeRequest, "[YOUR_APP_ID_HERE]", appKey); - /// await client.RevokeCardAsync(revokeRequest); - /// - /// How to get aliceCardModel and aliceKeys - /// - public async Task RevokeCardAsync(RevokeCardRequest request) - { - var snapshotModel = request.ExtractSnapshotModel(); - - var postRequest = Request.Create(RequestMethod.Delete) - .WithEndpoint($"/v4/card/{snapshotModel.CardId}") - .WithBody(request.GetRequestModel()); - - await this.CardsConnection.Send(postRequest).ConfigureAwait(false); - } - - - /// - /// Gets card by id. - /// - /// id of the card to get. - /// Found card from server response. - /// Get card model by id. - /// - /// var client = new VirgilClient("[YOUR_ACCESS_TOKEN_HERE]"); - /// var card = await client.GetCardAsync("[USER_CARD_ID_HERE]"); - /// - /// - public async Task GetCardAsync(string cardId) - { - var request = Request.Create(RequestMethod.Get) - .WithEndpoint($"/v4/card/{cardId}"); - - var resonse = await this.ReadCardsConnection.Send(request).ConfigureAwait(false); - var cardModel = resonse.Parse(); - - if (this.cardValidator != null) - { - this.ValidateCards(new[] { cardModel }); - } - - return cardModel; - } - - /// - /// Adds a relation for the Virgil Card to Virgil cards service. - /// - /// An instance of class, - /// that contains a trusted card snapshot. - /// Updated from server response. - /// if request doesn't have trusted - /// card's snapshot or doesn't have exactly 1 signature. - /// Example: - /// Look at to find out - /// how to publish bobCardModel and aliceCardModel. - /// - /// var addRelationRequest = new AddRelationRequest(bobCardModel.SnapshotModel); - /// requestSigner.AuthoritySign(addRelationRequest, aliceCardModel.Id, aliceKeys.PrivateKey); - /// var aliceCardModelWithRelation = await client.AddRelationAsync(addRelationRequest); - /// - /// - public async Task AddRelationAsync(AddRelationRequest request) - { - if (request == null || request.Snapshot.Length == 0 || request.Signatures.Count != 1) - { - throw new RelationException(); - } - var cardId = request.Signatures.Keys.First(); - var postRequest = Request.Create(RequestMethod.Post) - .WithEndpoint($"/v4/card/{cardId}/collections/relations") - .WithBody(request.GetRequestModel()); - - var response = await this.CardsConnection.Send(postRequest).ConfigureAwait(false); - var cardModel = response.Parse(); - - if (this.cardValidator != null) - { - this.ValidateCards(new[] { cardModel }); - } - - return cardModel; - } - - - /// - /// Deletes a relation for the Virgil Card to Virgil cards service. - /// - /// An instance of class, - /// that contains a trusted card id to be deleted from relations. - /// Updated from server response. - /// - /// Look at to find out - /// how to publish bobCardModel and aliceCardModel. - /// Look at to find out - /// how to add bobCardModel as a relation to aliceCardModel. - /// - /// var deleteRelationRequest = new DeleteRelationRequest(bobCardModel.Id, RevocationReason.Unspecified); - /// requestSigner.AuthoritySign(deleteRelationRequest, aliceCardModelWithRelation.Id, aliceKeys.PrivateKey); - /// var aliceCardModelWithoutRelation = await client.DeleteRelationAsync(deleteRelationRequest); - /// - /// - public async Task DeleteRelationAsync(DeleteRelationRequest request) - { - if (request == null || request.Snapshot.Length == 0 || request.Signatures.Count != 1) - { - throw new RelationException(); - } - var cardId = request.Signatures.Keys.First(); - var postRequest = Request.Create(RequestMethod.Delete) - .WithEndpoint($"/v4/card/{cardId}/collections/relations") - .WithBody(request.GetRequestModel()); - - var response = await this.CardsConnection.Send(postRequest).ConfigureAwait(false); - var cardModel = response.Parse(); - - if (this.cardValidator != null) - { - this.ValidateCards(new[] { cardModel }); - } - - return cardModel; - } - - /// - /// Sends the request for identity verification, that's will be processed depending of specified type. - /// - /// An unique string that represents identity. - /// The type of identity. - /// The extra fields. - /// The action identifier that is required for confirmation the identity. - /// - /// Use method to confirm and get the indentity token. - /// - public async Task VerifyIdentityAsync - ( - string identity, - string identityType, - IDictionary extraFields = null - ) - { - var body = new - { - type = identityType, - value = identity, - extra_fields = extraFields - }; - - var request = Request.Create(RequestMethod.Post) - .WithBody(body) - .WithEndpoint("v1/verify"); - - var response = await this.IdentityConnection.Send(request).ConfigureAwait(false); - var result = response.Parse(); - - return result.ActionId; - } - - /// - /// Confirms the identity using confirmation code, that has been generated to confirm an identity. - /// - /// The action identifier that was obtained on verification step. - /// The confirmation code that was recived on email box. - /// The time to live. - /// The count to live. - /// A string that represent an identity validattion token. - public async Task ConfirmIdentityAsync(Guid actionId, string code, int timeToLive = 3600, int countToLive = 1) - { - var body = new - { - confirmation_code = code, - action_id = actionId, - token = new - { - time_to_live = timeToLive, - count_to_live = countToLive - } - }; - - var request = Request.Create(RequestMethod.Post) - .WithBody(body) - .WithEndpoint("v1/confirm"); - - var response = await this.IdentityConnection.Send(request).ConfigureAwait(false); - var result = response.Parse(); - - return result.ValidationToken; - } - - /// - /// Returns true if validation token is valid. - /// - /// The type of identity. - /// The identity value. - /// The validation token. - public async Task IsIdentityValid(string identityValue, string identityType, string validationToken) - { - var request = Request.Create(RequestMethod.Post) - .WithBody(new - { - value = identityValue, - type = identityType, - validation_token = validationToken - }) - .WithEndpoint("v1/validate"); - - var response = await this.IdentityConnection.Send(request, true).ConfigureAwait(false); - return response.StatusCode == 400; - } - - #region Private Methods - - private void ValidateCards(IEnumerable cards) - { - var foundCards = cards.ToList(); - - var invalidCards = foundCards.Where(c => !this.cardValidator.Validate(c)).ToList(); - if (invalidCards.Any()) - { - throw new CardValidationException(invalidCards); - } - } - - private IConnection InitializeIdentityConnection() - { - var baseUrl = new Uri(this.parameters.IdentityServiceAddress); - return new IdentityServiceConnection(this.parameters.AccessToken, baseUrl); - } - - private IConnection InitializeRAConnection() - { - var baseUrl = new Uri(this.parameters.RAServiceAddress); - return new RAServiceConnection(this.parameters.AccessToken, baseUrl); - } - - private IConnection InitializeReadCardsConnection() - { - var baseUrl = new Uri(this.parameters.ReadOnlyCardsServiceAddress); - return new CardsServiceConnection(this.parameters.AccessToken, baseUrl); - } - - private IConnection InitializeCardsConnection() - { - var baseUrl = new Uri(this.parameters.CardsServiceAddress); - return new CardsServiceConnection(this.parameters.AccessToken, baseUrl); - } - - #endregion - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/VirgilClientParams.cs b/SDK/Source/Virgil.SDK.Shared/Client/VirgilClientParams.cs deleted file mode 100644 index 388b9e7a..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Client/VirgilClientParams.cs +++ /dev/null @@ -1,149 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Client -{ - using System; - - public class VirgilClientParams - { - /// - /// Initializes a new instance of the class. - /// - public VirgilClientParams() : this(null) - { - } - - /// - /// Initializes a new instance of the class. - /// - public VirgilClientParams(string accessToken) - { - this.AccessToken = accessToken; - - this.CardsServiceAddress = "https://cards.virgilsecurity.com"; - this.ReadOnlyCardsServiceAddress = "https://cards-ro.virgilsecurity.com"; - this.IdentityServiceAddress = "https://identity.virgilsecurity.com"; - this.RAServiceAddress = "https://ra.virgilsecurity.com/"; - } - - /// - /// Gets the access token. - /// - internal string AccessToken { get; } - - /// - /// Gets the cards service URL. - /// - internal string CardsServiceAddress { get; private set; } - - /// - /// Gets the read only cards service address. - /// - internal string ReadOnlyCardsServiceAddress { get; private set; } - - /// - /// Gets the identity service address. - /// - internal string IdentityServiceAddress { get; private set; } - - /// - /// Gets the Registration Authority service address. - /// - internal string RAServiceAddress { get; private set; } - - /// - /// Sets the Registration Authority service address. - /// - /// The service address. - /// - public void SetRAServiceAddress(string serviceAddress) - { - if (string.IsNullOrWhiteSpace(serviceAddress) && !CheckServiceUrl(serviceAddress)) - throw new ArgumentException(nameof(serviceAddress)); - - this.RAServiceAddress = serviceAddress; - } - - /// - /// Sets the identity service address. - /// - /// The service address. - /// - public void SetIdentityServiceAddress(string serviceAddress) - { - if (string.IsNullOrWhiteSpace(serviceAddress) && !CheckServiceUrl(serviceAddress)) - throw new ArgumentException(nameof(serviceAddress)); - - this.IdentityServiceAddress = serviceAddress; - } - - /// - /// Sets the cards service address. - /// - /// The service address. - /// - public void SetCardsServiceAddress(string serviceAddress) - { - if (string.IsNullOrWhiteSpace(serviceAddress) && !CheckServiceUrl(serviceAddress)) - throw new ArgumentException(nameof(serviceAddress)); - - this.CardsServiceAddress = serviceAddress; - } - - /// - /// Sets the cards service address. - /// - /// The service address. - /// - public void SetReadCardsServiceAddress(string serviceAddress) - { - if (string.IsNullOrWhiteSpace(serviceAddress) && !CheckServiceUrl(serviceAddress)) - throw new ArgumentException(nameof(serviceAddress)); - - this.ReadOnlyCardsServiceAddress = serviceAddress; - } - - private static bool CheckServiceUrl(string serviceUrl) - { - Uri uriResult; - var isValid = Uri.TryCreate(serviceUrl, UriKind.Absolute, out uriResult) - && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); - - return isValid; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Common/Base64Url.cs b/SDK/Source/Virgil.SDK.Shared/Common/Base64Url.cs new file mode 100644 index 00000000..5504770f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/Base64Url.cs @@ -0,0 +1,36 @@ +using System; + +namespace Virgil.SDK.Common +{ + public class Base64Url + { + public static string Encode(byte[] data) + { + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_').Trim('='); + } + + public static byte[] Decode(string base64str) + { + if (string.IsNullOrWhiteSpace(base64str)) + { + throw new ArgumentException(nameof(base64str)); + } + var urlDecoded = base64str.Replace('-', '+').Replace('_', '/'); + switch (urlDecoded.Length % 4) + { + case 2: + urlDecoded += "=="; + break; + case 3: + urlDecoded += "="; + break; + } + var bytes = Convert.FromBase64String(urlDecoded); + return bytes; + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/Bytes.cs b/SDK/Source/Virgil.SDK.Shared/Common/Bytes.cs new file mode 100644 index 00000000..443243d5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/Bytes.cs @@ -0,0 +1,132 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.SDK.Common +{ + using System; + using System.Text; + using System.Linq; + + public class Bytes + { + /// + /// Combines several byte arrays into one. + /// + public static byte[] Combine(params byte[][] arrays) + { + var rv = new byte[arrays.Sum(a => a.Length)]; + var offset = 0; + foreach (var array in arrays) + { + Buffer.BlockCopy(array, 0, rv, offset, array.Length); + offset += array.Length; + } + return rv; + } + + /// + /// Decodes the current to a string according to the specified + /// character encoding in . + /// + /// + /// The character encoding to decode to. + /// + /// A that represents this instance. + /// + public static string ToString(byte[] inputBytes, StringEncoding encoding = StringEncoding.UTF8) + { + if (inputBytes == null) + { + throw new ArgumentNullException(nameof(inputBytes)); + } + switch (encoding) + { + case StringEncoding.BASE64: + return Convert.ToBase64String(inputBytes); + case StringEncoding.HEX: + var hex = BitConverter.ToString(inputBytes); + return hex.Replace("-", "").ToLower(); + case StringEncoding.UTF8: + return Encoding.UTF8.GetString(inputBytes); + default: + throw new ArgumentOutOfRangeException(nameof(encoding), encoding, null); + } + } + + /// + /// Creates a new containing the given string. If provided, the encoding parameter + /// identifies the character encoding of string. + /// + /// String to encode. + /// The encoding of string. + /// + public static byte[] FromString(string str, StringEncoding encoding = StringEncoding.UTF8) + { + if (str == null) + { + throw new ArgumentNullException(nameof(str)); + } + switch (encoding) + { + case StringEncoding.BASE64: + return Convert.FromBase64String(str); + case StringEncoding.HEX: + return FromHEXString(str); + case StringEncoding.UTF8: + return Encoding.UTF8.GetBytes(str); + default: + throw new ArgumentOutOfRangeException(nameof(encoding), encoding, null); + } + } + + /// + /// Get bytes from specified string, which encodes binary + /// data as hexadecimal digits. + /// + private static byte[] FromHEXString(string str) + { + var numberChars = str.Length; + var bytes = new byte[numberChars / 2]; + + for (var i = 0; i < numberChars; i += 2) + { + bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16); + } + + return bytes; + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/CardExporter.cs b/SDK/Source/Virgil.SDK.Shared/Common/CardExporter.cs deleted file mode 100644 index 9e91b3e8..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Common/CardExporter.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Virgil.SDK.Shared -{ - using Virgil.SDK.Client; - - public class CardExporter - { - public CardExporter() - { - } - - public void Export(CardModel cardModel) - { - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/CardUtils.cs b/SDK/Source/Virgil.SDK.Shared/Common/CardUtils.cs new file mode 100644 index 00000000..263d6b83 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/CardUtils.cs @@ -0,0 +1,176 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Virgil.SDK.Signer; + +namespace Virgil.SDK.Common +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Virgil.CryptoAPI; + using Virgil.SDK.Web; + + public class CardUtils + { + public static string GenerateCardId(ICardCrypto cardCrypto, byte[] snapshot) + { + ValidateGenerateCardIdParams(cardCrypto, snapshot); + var fingerprint = cardCrypto.GenerateSHA512(snapshot); + var id = Bytes.ToString(fingerprint.Take(32).ToArray(), StringEncoding.HEX); + return id; + } + + private static void ValidateGenerateCardIdParams(ICardCrypto cardCrypto, byte[] snapshot) + { + if (cardCrypto == null) + { + throw new ArgumentNullException(nameof(cardCrypto)); + } + + if (snapshot == null) + { + throw new ArgumentNullException(nameof(snapshot)); + } + } + + /// + /// Loads from the specified . + /// + /// an instance of . + /// an instance of to get + /// from. + /// + /// Loaded instance of . + public static Card Parse(ICardCrypto cardCrypto, RawSignedModel rawSignedModel, bool isOutdated = false) + { + ValidateParams(cardCrypto, rawSignedModel); + + var rawCardContent = SnapshotUtils.ParseSnapshot(rawSignedModel.ContentSnapshot); + + var signatures = new List(); + if (rawSignedModel.Signatures != null) + { + foreach (var s in rawSignedModel.Signatures) + { + var cardSignature = new CardSignature + { + Signer = s.Signer, + Signature = s.Signature, + ExtraFields = TryParseExtraFields(s.Snapshot), + Snapshot = s.Snapshot + }; + signatures.Add(cardSignature); + } + } + + return new Card( + GenerateCardId(cardCrypto, rawSignedModel.ContentSnapshot), + rawCardContent.Identity, + cardCrypto.ImportPublicKey(rawCardContent.PublicKey), + rawCardContent.Version, + rawCardContent.CreatedAt, + signatures, + rawCardContent.PreviousCardId, + rawSignedModel.ContentSnapshot, + isOutdated + ); + } + + private static void ValidateParams(ICardCrypto cardCrypto, RawSignedModel rawSignedModel) + { + if (rawSignedModel == null) + { + throw new ArgumentNullException(nameof(rawSignedModel)); + } + + if (cardCrypto == null) + { + throw new ArgumentNullException(nameof(cardCrypto)); + } + } + + private static Dictionary TryParseExtraFields(byte[] signatureSnapshot) + { + Dictionary extraFields = null; + if (signatureSnapshot != null) + { + try + { + extraFields = SnapshotUtils.ParseSnapshot>(signatureSnapshot); + } + catch (Exception) + { + } + } + return extraFields; + } + + public static IList Parse(ICardCrypto cardCrypto, IEnumerable requests) + { + if (requests == null) + { + throw new ArgumentNullException(nameof(requests)); + } + + return requests.Select(r => CardUtils.Parse(cardCrypto, r)).ToList(); + } + + public static IList LinkedCardLists(Card[] cards) + { + var unsorted = new Dictionary(); + foreach (var card in cards) + { + unsorted.Add(card.Id, card); + } + + foreach (var card in cards) + { + if (card.PreviousCardId != null) + { + if (unsorted[card.PreviousCardId] != null) + { + unsorted[card.PreviousCardId].IsOutdated = true; + card.PreviousCard = unsorted[card.PreviousCardId]; + unsorted.Remove(card.PreviousCardId); + } + } + } + return unsorted.Values.ToList(); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Common/CardValidator.cs b/SDK/Source/Virgil.SDK.Shared/Common/CardValidator.cs deleted file mode 100644 index 6a119049..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Common/CardValidator.cs +++ /dev/null @@ -1,135 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Common -{ - using System; - using System.Collections.Generic; - using System.Linq; - - using Virgil.SDK.Cryptography; - using Virgil.SDK.Client; - - /// - /// This class provides a methods for validating , by default - /// it validates self and service signatures. - /// - public class CardValidator : ICardValidator - { - private readonly ICrypto crypto; - private readonly Dictionary verifiers; - - private const string ServiceCardId = "3e29d43373348cfb373b7eae189214dc01d7237765e572db685839b64adca853"; - private const string ServicePublicKey = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQVlSNTAx" + - "a1YxdFVuZTJ1T2RrdzRrRXJSUmJKcmMyU3lhejVWMWZ1RytyVnM9Ci0tLS0tRU5E" + - "IFBVQkxJQyBLRVktLS0tLQo="; - /// - /// Initializes a new instance of the class. - /// - public CardValidator(ICrypto crypto) - { - this.crypto = crypto; - this.verifiers = new Dictionary(); - } - - /// - /// Add default service verifiers to validator - /// - public void AddDefaultVerifiers() - { - var servicePublicKey = crypto.ImportPublicKey(Convert.FromBase64String(ServicePublicKey)); - this.verifiers.Add(ServiceCardId, servicePublicKey); - } - - /// - /// Adds the signature verifier. - /// - public void AddVerifier(string verifierCardId, byte[] verifierPublicKey) - { - if (string.IsNullOrWhiteSpace(verifierCardId)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(verifierCardId)); - - if (verifierPublicKey == null) - throw new ArgumentNullException(nameof(verifierPublicKey)); - - var publicKey = this.crypto.ImportPublicKey(verifierPublicKey); - this.verifiers.Add(verifierCardId, publicKey); - } - - /// - /// Validates a using pined Public Keys. - /// - public virtual bool Validate(CardModel card) - { - // Support for legacy Cards. - if (card.Meta.Version == "3.0" && card.SnapshotModel.Scope == CardScope.Global) - { - return true; - } - - var fingerprint = this.crypto.CalculateFingerprint(card.Snapshot); - var fingerprintHex = fingerprint.ToHEX(); - - if (fingerprintHex != card.Id) - { - return false; - } - - // add self signature verifier - - var allVerifiers = this.verifiers.ToDictionary(it => it.Key, it => it.Value); - allVerifiers.Add(fingerprintHex, this.crypto.ImportPublicKey(card.SnapshotModel.PublicKeyData)); - - foreach (var verifier in allVerifiers) - { - if (!card.Meta.Signatures.ContainsKey(verifier.Key)) - { - return false; - } - - var isValid = this.crypto.Verify(fingerprint.GetValue(), - card.Meta.Signatures[verifier.Key], verifier.Value); - - if (!isValid) - { - return false; - } - } - - return true; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestValidationModel.cs b/SDK/Source/Virgil.SDK.Shared/Common/IJsonSerializer.cs similarity index 87% rename from SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestValidationModel.cs rename to SDK/Source/Virgil.SDK.Shared/Common/IJsonSerializer.cs index 273ff9e5..ab4b70f0 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestValidationModel.cs +++ b/SDK/Source/Virgil.SDK.Shared/Common/IJsonSerializer.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,13 +34,11 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Common { - using Newtonsoft.Json; - - internal class SignableRequestValidationModel + public interface IJsonSerializer { - [JsonProperty("token")] - public string Token { get; set; } + string Serialize(object model); + TModel Deserialize(string json); } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/ObjectSnapshotter.cs b/SDK/Source/Virgil.SDK.Shared/Common/ObjectSnapshotter.cs deleted file mode 100644 index 73310595..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Common/ObjectSnapshotter.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Virgil.SDK.Common -{ - using System.Text; - - /// - /// The class provides a list of methods to take an accurate snapshot of the object, - /// and convert it into the binary data. - /// - internal class Snapshotter - { - internal byte[] Capture(object snapshotModel) - { - var snapshotModelJson = JsonSerializer.Serialize(snapshotModel); - var takenSnapshot = Encoding.UTF8.GetBytes(snapshotModelJson); - - return takenSnapshot; - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/PetaJson.cs b/SDK/Source/Virgil.SDK.Shared/Common/PetaJson.cs new file mode 100644 index 00000000..4e06bf9c --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/PetaJson.cs @@ -0,0 +1,3362 @@ +// PetaJson v0.5 - A simple but flexible Json library in a single .cs file. +// +// Copyright (C) 2014 Topten Software (contact@toptensoftware.com) All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this product +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +#define PETAJSON_NO_DYNAMIC +#define PETAJSON_NO_EMIT +// Define PETAJSON_NO_DATACONTRACT to disable support for [DataContract]/[DataMember] + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; +using System.Globalization; +using System.Collections; +using System.Threading; +#if !PETAJSON_NO_DYNAMIC +using System.Dynamic; +#endif +#if !PETAJSON_NO_EMIT +using System.Reflection.Emit; +#endif +#if !PETAJSON_NO_DATACONTRACT +using System.Runtime.Serialization; +#endif + + + +namespace Virgil.SDK.Common.PetaJson +{ + // Pass to format/write/parse functions to override defaults + [Flags] + public enum JsonOptions + { + None = 0, + WriteWhitespace = 0x00000001, + DontWriteWhitespace = 0x00000002, + StrictParser = 0x00000004, + NonStrictParser = 0x00000008, + Flush = 0x00000010, + AutoSavePreviousVersion = 0x00000020, // Use "SavePreviousVersions" static property + SavePreviousVersion = 0x00000040 // Always save previous version + } + + // API + public static class Json + { + static Json() + { + WriteWhitespaceDefault = false; + StrictParserDefault = false; + +#if !PETAJSON_NO_EMIT + Json.SetFormatterResolver(Internal.Emit.MakeFormatter); + Json.SetParserResolver(Internal.Emit.MakeParser); + Json.SetIntoParserResolver(Internal.Emit.MakeIntoParser); +#endif + } + + // Pretty format default + public static bool WriteWhitespaceDefault + { + get; + set; + } + + // Strict parser + public static bool StrictParserDefault + { + get; + set; + } + + // Write an object to a text writer + public static void Write(TextWriter w, object o, JsonOptions options = JsonOptions.None) + { + var writer = new Internal.Writer(w, ResolveOptions(options)); + writer.WriteValue(o); + } + + static void DeleteFile(string filename) + { + try + { + System.IO.File.Delete(filename); + } + catch + { + // Don't care + } + } + + public static bool SavePreviousVersions + { + get; + set; + } + + // Write a file atomically by writing to a temp file and then renaming it - prevents corrupted files if crash + // in middle of writing file. + public static void WriteFileAtomic(string filename, object o, JsonOptions options = JsonOptions.None, string backupFilename = null) + { + var tempName = filename + ".tmp"; + + try + { + // Write the temp file + WriteFile(tempName, o, (options | JsonOptions.Flush)); + + if (System.IO.File.Exists(filename)) + { + bool savePreviousVersion = false; + + if ((options & JsonOptions.AutoSavePreviousVersion) != 0) + { + savePreviousVersion = SavePreviousVersions; + } + else if ((options & JsonOptions.SavePreviousVersion) != 0) + { + savePreviousVersion = true; + } + + + // Work out backup filename + if (savePreviousVersion) + { + // Make sure have a backup filename + if (backupFilename == null) + { + backupFilename = filename + ".previous"; + } + } + else + { + // No backup + backupFilename = null; + } + + // Replace it + File.Replace(tempName, filename, backupFilename); + } + else + { + // Rename it + File.Move(tempName, filename); + } + } + catch + { + DeleteFile(tempName); + throw; + } + } + + // Write an object to a file + public static void WriteFile(string filename, object o, JsonOptions options = JsonOptions.None) + { + using (var w = new StreamWriter(filename)) + { + Write(w, o, options); + + if ((options & JsonOptions.Flush) != 0) + { + w.Flush(); + w.BaseStream.Flush(); + } + } + } + + // Format an object as a json string + public static string Format(object o, JsonOptions options = JsonOptions.None) + { + var sw = new StringWriter(); + var writer = new Internal.Writer(sw, ResolveOptions(options)); + writer.WriteValue(o); + return sw.ToString(); + } + + // Parse an object of specified type from a text reader + public static object Parse(TextReader r, Type type, JsonOptions options = JsonOptions.None) + { + Internal.Reader reader = null; + try + { + reader = new Internal.Reader(r, ResolveOptions(options)); + var retv = reader.Parse(type); + reader.CheckEOF(); + return retv; + } + catch (Exception x) + { + var loc = reader == null ? new JsonLineOffset() : reader.CurrentTokenPosition; + Console.WriteLine("Exception thrown while parsing JSON at {0}, context:{1}\n{2}", loc, reader.Context, x.ToString()); + throw new JsonParseException(x, reader.Context, loc); + } + } + + // Parse an object of specified type from a text reader + public static T Parse(TextReader r, JsonOptions options = JsonOptions.None) + { + return (T)Parse(r, typeof(T), options); + } + + // Parse from text reader into an already instantied object + public static void ParseInto(TextReader r, Object into, JsonOptions options = JsonOptions.None) + { + if (into == null) + throw new NullReferenceException(); + if (into.GetType().IsValueType) + throw new InvalidOperationException("Can't ParseInto a value type"); + + Internal.Reader reader = null; + try + { + reader = new Internal.Reader(r, ResolveOptions(options)); + reader.ParseInto(into); + reader.CheckEOF(); + } + catch (Exception x) + { + var loc = reader == null ? new JsonLineOffset() : reader.CurrentTokenPosition; + Console.WriteLine("Exception thrown while parsing JSON at {0}, context:{1}\n{2}", loc, reader.Context, x.ToString()); + throw new JsonParseException(x, reader.Context, loc); + } + } + + // Parse an object of specified type from a file + public static object ParseFile(string filename, Type type, JsonOptions options = JsonOptions.None) + { + using (var r = new StreamReader(filename)) + { + return Parse(r, type, options); + } + } + + // Parse an object of specified type from a file + public static T ParseFile(string filename, JsonOptions options = JsonOptions.None) + { + using (var r = new StreamReader(filename)) + { + return Parse(r, options); + } + } + + // Parse from file into an already instantied object + public static void ParseFileInto(string filename, Object into, JsonOptions options = JsonOptions.None) + { + using (var r = new StreamReader(filename)) + { + ParseInto(r, into, options); + } + } + + // Parse an object from a string + public static object Parse(string data, Type type, JsonOptions options = JsonOptions.None) + { + return Parse(new StringReader(data), type, options); + } + + // Parse an object from a string + public static T Parse(string data, JsonOptions options = JsonOptions.None) + { + return (T)Parse(new StringReader(data), options); + } + + // Parse from string into an already instantiated object + public static void ParseInto(string data, Object into, JsonOptions options = JsonOptions.None) + { + ParseInto(new StringReader(data), into, options); + } + + // Create a clone of an object + public static T Clone(T source) + { + return (T)Reparse(source.GetType(), source); + } + + // Create a clone of an object (untyped) + public static object Clone(object source) + { + return Reparse(source.GetType(), source); + } + + // Clone an object into another instance + public static void CloneInto(object dest, object source) + { + ReparseInto(dest, source); + } + + // Reparse an object by writing to a stream and re-reading (possibly + // as a different type). + public static object Reparse(Type type, object source) + { + if (source == null) + return null; + var ms = new MemoryStream(); + try + { + // Write + var w = new StreamWriter(ms); + Json.Write(w, source); + w.Flush(); + + // Read + ms.Seek(0, SeekOrigin.Begin); + var r = new StreamReader(ms); + return Json.Parse(r, type); + } + finally + { + ms.Dispose(); + } + } + + // Typed version of above + public static T Reparse(object source) + { + return (T)Reparse(typeof(T), source); + } + + // Reparse one object into another object + public static void ReparseInto(object dest, object source) + { + var ms = new MemoryStream(); + try + { + // Write + var w = new StreamWriter(ms); + Json.Write(w, source); + w.Flush(); + + // Read + ms.Seek(0, SeekOrigin.Begin); + var r = new StreamReader(ms); + Json.ParseInto(r, dest); + } + finally + { + ms.Dispose(); + } + } + + // Register a callback that can format a value of a particular type into json + public static void RegisterFormatter(Type type, Action formatter) + { + Internal.Writer._formatters[type] = formatter; + } + + // Typed version of above + public static void RegisterFormatter(Action formatter) + { + RegisterFormatter(typeof(T), (w, o) => formatter(w, (T)o)); + } + + // Register a parser for a specified type + public static void RegisterParser(Type type, Func parser) + { + Internal.Reader._parsers.Set(type, parser); + } + + // Register a typed parser + public static void RegisterParser(Func parser) + { + RegisterParser(typeof(T), (r, t) => parser(r, t)); + } + + // Simpler version for simple types + public static void RegisterParser(Type type, Func parser) + { + RegisterParser(type, (r, t) => r.ReadLiteral(parser)); + } + + // Simpler and typesafe parser for simple types + public static void RegisterParser(Func parser) + { + RegisterParser(typeof(T), literal => parser(literal)); + } + + // Register an into parser + public static void RegisterIntoParser(Type type, Action parser) + { + Internal.Reader._intoParsers.Set(type, parser); + } + + // Register an into parser + public static void RegisterIntoParser(Action parser) + { + RegisterIntoParser(typeof(T), parser); + } + + // Register a factory for instantiating objects (typically abstract classes) + // Callback will be invoked for each key in the dictionary until it returns an object + // instance and which point it will switch to serialization using reflection + public static void RegisterTypeFactory(Type type, Func factory) + { + Internal.Reader._typeFactories.Set(type, factory); + } + + // Register a callback to provide a formatter for a newly encountered type + public static void SetFormatterResolver(Func> resolver) + { + Internal.Writer._formatterResolver = resolver; + } + + // Register a callback to provide a parser for a newly encountered value type + public static void SetParserResolver(Func> resolver) + { + Internal.Reader._parserResolver = resolver; + } + + // Register a callback to provide a parser for a newly encountered reference type + public static void SetIntoParserResolver(Func> resolver) + { + Internal.Reader._intoParserResolver = resolver; + } + + public static bool WalkPath(this IDictionary This, string Path, bool create, Func, string, bool> leafCallback) + { + // Walk the path + var parts = Path.Split('.'); + for (int i = 0; i < parts.Length - 1; i++) + { + object val; + if (!This.TryGetValue(parts[i], out val)) + { + if (!create) + return false; + + val = new Dictionary(); + This[parts[i]] = val; + } + This = (IDictionary)val; + } + + // Process the leaf + return leafCallback(This, parts[parts.Length - 1]); + } + + public static bool PathExists(this IDictionary This, string Path) + { + return This.WalkPath(Path, false, (dict, key) => dict.ContainsKey(key)); + } + + public static object GetPath(this IDictionary This, Type type, string Path, object def) + { + This.WalkPath(Path, false, (dict, key) => + { + object val; + if (dict.TryGetValue(key, out val)) + { + if (val == null) + def = val; + else if (type.IsAssignableFrom(val.GetType())) + def = val; + else + def = Reparse(type, val); + } + return true; + }); + + return def; + } + + // Ensure there's an object of type T at specified path + public static T GetObjectAtPath(this IDictionary This, string Path) where T : class, new() + { + T retVal = null; + This.WalkPath(Path, true, (dict, key) => + { + object val; + dict.TryGetValue(key, out val); + retVal = val as T; + if (retVal == null) + { + retVal = val == null ? new T() : Reparse(val); + dict[key] = retVal; + } + return true; + }); + + return retVal; + } + + public static T GetPath(this IDictionary This, string Path, T def = default(T)) + { + return (T)This.GetPath(typeof(T), Path, def); + } + + public static void SetPath(this IDictionary This, string Path, object value) + { + This.WalkPath(Path, true, (dict, key) => { dict[key] = value; return true; }); + } + + // Resolve passed options + static JsonOptions ResolveOptions(JsonOptions options) + { + JsonOptions resolved = JsonOptions.None; + + if ((options & (JsonOptions.WriteWhitespace | JsonOptions.DontWriteWhitespace)) != 0) + resolved |= options & (JsonOptions.WriteWhitespace | JsonOptions.DontWriteWhitespace); + else + resolved |= WriteWhitespaceDefault ? JsonOptions.WriteWhitespace : JsonOptions.DontWriteWhitespace; + + if ((options & (JsonOptions.StrictParser | JsonOptions.NonStrictParser)) != 0) + resolved |= options & (JsonOptions.StrictParser | JsonOptions.NonStrictParser); + else + resolved |= StrictParserDefault ? JsonOptions.StrictParser : JsonOptions.NonStrictParser; + + return resolved; + } + } + + // Called before loading via reflection + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonLoading + { + void OnJsonLoading(IJsonReader r); + } + + // Called after loading via reflection + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonLoaded + { + void OnJsonLoaded(IJsonReader r); + } + + // Called for each field while loading from reflection + // Return true if handled + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonLoadField + { + bool OnJsonField(IJsonReader r, string key); + } + + // Called when about to write using reflection + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonWriting + { + void OnJsonWriting(IJsonWriter w); + } + + // Called after written using reflection + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonWritten + { + void OnJsonWritten(IJsonWriter w); + } + + // Describes the current literal in the json stream + public enum LiteralKind + { + None, + String, + Null, + True, + False, + SignedInteger, + UnsignedInteger, + FloatingPoint, + } + + // Passed to registered parsers + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonReader + { + object Parse(Type type); + T Parse(); + void ParseInto(object into); + + object ReadLiteral(Func converter); + void ParseDictionary(Action callback); + void ParseArray(Action callback); + + LiteralKind GetLiteralKind(); + string GetLiteralString(); + void NextToken(); + } + + // Passed to registered formatters + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public interface IJsonWriter + { + void WriteStringLiteral(string str); + void WriteRaw(string str); + void WriteArray(Action callback); + void WriteDictionary(Action callback); + void WriteValue(object value); + void WriteElement(); + void WriteKey(string key); + void WriteKeyNoEscaping(string key); + } + + // Exception thrown for any parse error + public class JsonParseException : Exception + { + public JsonParseException(Exception inner, string context, JsonLineOffset position) : + base(string.Format("JSON parse error at {0}{1} - {2}", position, string.IsNullOrEmpty(context) ? "" : string.Format(", context {0}", context), inner.Message), inner) + { + Position = position; + Context = context; + } + public JsonLineOffset Position; + public string Context; + } + + // Represents a line and character offset position in the source Json + public struct JsonLineOffset + { + public int Line; + public int Offset; + public override string ToString() + { + return string.Format("line {0}, character {1}", Line + 1, Offset + 1); + } + } + + // Used to decorate fields and properties that should be serialized + // + // - [Json] on class or struct causes all public fields and properties to be serialized + // - [Json] on a public or non-public field or property causes that member to be serialized + // - [JsonExclude] on a field or property causes that field to be not serialized + // - A class or struct with no [Json] attribute has all public fields/properties serialized + // - A class or struct with no [Json] attribute but a [Json] attribute on one or more members only serializes those members + // + // Use [Json("keyname")] to explicitly specify the key to be used + // [Json] without the keyname will be serialized using the name of the member with the first letter lowercased. + // + // [Json(KeepInstance=true)] causes container/subobject types to be serialized into the existing member instance (if not null) + // + // You can also use the system supplied DataContract and DataMember attributes. They'll only be used if there + // are no PetaJson attributes on the class or it's members. You must specify DataContract on the type and + // DataMember on any fields/properties that require serialization. There's no need for exclude attribute. + // When using DataMember, the name of the field or property is used as is - the first letter is left in upper case + // + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field)] + public class JsonAttribute : Attribute + { + public JsonAttribute() + { + _key = null; + } + + public JsonAttribute(string key) + { + _key = key; + } + + // Key used to save this field/property + string _key; + public string Key + { + get { return _key; } + } + + // If true uses ParseInto to parse into the existing object instance + // If false, creates a new instance as assigns it to the property + public bool KeepInstance + { + get; + set; + } + + // If true, the property will be loaded, but not saved + // Use to upgrade deprecated persisted settings, but not + // write them back out again + public bool Deprecated + { + get; + set; + } + } + + // See comments for JsonAttribute above + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class JsonExcludeAttribute : Attribute + { + public JsonExcludeAttribute() + { + } + } + + + // Apply to enum values to specify which enum value to select + // if the supplied json value doesn't match any. + // If not found throws an exception + // eg, any unknown values in the json will be mapped to Fruit.unknown + // + // [JsonUnknown(Fruit.unknown)] + // enum Fruit + // { + // unknown, + // Apple, + // Pear, + // } + [AttributeUsage(AttributeTargets.Enum)] + public class JsonUnknownAttribute : Attribute + { + public JsonUnknownAttribute(object unknownValue) + { + UnknownValue = unknownValue; + } + + public object UnknownValue + { + get; + private set; + } + } + + namespace Internal + { + [Obfuscation(Exclude = true, ApplyToMembers = true)] + public enum Token + { + EOF, + Identifier, + Literal, + OpenBrace, + CloseBrace, + OpenSquare, + CloseSquare, + Equal, + Colon, + SemiColon, + Comma, + } + + // Helper to create instances but include the type name in the thrown exception + public static class DecoratingActivator + { + public static object CreateInstance(Type t) + { + try + { + return Activator.CreateInstance(t, true); + } + catch (Exception x) + { + throw new InvalidOperationException(string.Format("Failed to create instance of type '{0}'", t.FullName), x); + } + } + } + + public class Reader : IJsonReader + { + static Reader() + { + // Setup default resolvers + _parserResolver = ResolveParser; + _intoParserResolver = ResolveIntoParser; + + Func simpleConverter = (reader, type) => + { + return reader.ReadLiteral(literal => Convert.ChangeType(literal, type, CultureInfo.InvariantCulture)); + }; + + Func numberConverter = (reader, type) => + { + switch (reader.GetLiteralKind()) + { + case LiteralKind.SignedInteger: + case LiteralKind.UnsignedInteger: + case LiteralKind.FloatingPoint: + object val = Convert.ChangeType(reader.GetLiteralString(), type, CultureInfo.InvariantCulture); + reader.NextToken(); + return val; + } + throw new InvalidDataException("expected a numeric literal"); + }; + + // Default type handlers + _parsers.Set(typeof(string), simpleConverter); + _parsers.Set(typeof(char), simpleConverter); + _parsers.Set(typeof(bool), simpleConverter); + _parsers.Set(typeof(byte), numberConverter); + _parsers.Set(typeof(sbyte), numberConverter); + _parsers.Set(typeof(short), numberConverter); + _parsers.Set(typeof(ushort), numberConverter); + _parsers.Set(typeof(int), numberConverter); + _parsers.Set(typeof(uint), numberConverter); + _parsers.Set(typeof(long), numberConverter); + _parsers.Set(typeof(ulong), numberConverter); + _parsers.Set(typeof(decimal), numberConverter); + _parsers.Set(typeof(float), numberConverter); + _parsers.Set(typeof(double), numberConverter); + _parsers.Set(typeof(DateTime), (reader, type) => + { + return reader.ReadLiteral(literal => Utils.FromUnixMilliseconds((long)Convert.ChangeType(literal, typeof(long), CultureInfo.InvariantCulture))); + }); + _parsers.Set(typeof(byte[]), (reader, type) => + { + return reader.ReadLiteral(literal => Convert.FromBase64String((string)Convert.ChangeType(literal, typeof(string), CultureInfo.InvariantCulture))); + }); + } + + public Reader(TextReader r, JsonOptions options) + { + _tokenizer = new Tokenizer(r, options); + _options = options; + } + + Tokenizer _tokenizer; + JsonOptions _options; + List _contextStack = new List(); + + public string Context + { + get + { + return string.Join(".", _contextStack); + } + } + + static Action ResolveIntoParser(Type type) + { + var ri = ReflectionInfo.GetReflectionInfo(type); + if (ri != null) + return ri.ParseInto; + else + return null; + } + + static Func ResolveParser(Type type) + { + // See if the Type has a static parser method - T ParseJson(IJsonReader) + var parseJson = ReflectionInfo.FindParseJson(type); + if (parseJson != null) + { + if (parseJson.GetParameters()[0].ParameterType == typeof(IJsonReader)) + { + return (r, t) => parseJson.Invoke(null, new Object[] { r }); + } + else + { + return (r, t) => + { + if (r.GetLiteralKind() == LiteralKind.String) + { + var o = parseJson.Invoke(null, new Object[] { r.GetLiteralString() }); + r.NextToken(); + return o; + } + throw new InvalidDataException(string.Format("Expected string literal for type {0}", type.FullName)); + }; + } + } + + return (r, t) => + { + var into = DecoratingActivator.CreateInstance(type); + r.ParseInto(into); + return into; + }; + } + + public JsonLineOffset CurrentTokenPosition + { + get { return _tokenizer.CurrentTokenPosition; } + } + + // ReadLiteral is implemented with a converter callback so that any + // errors on converting to the target type are thrown before the tokenizer + // is advanced to the next token. This ensures error location is reported + // at the start of the literal, not the following token. + public object ReadLiteral(Func converter) + { + _tokenizer.Check(Token.Literal); + var retv = converter(_tokenizer.LiteralValue); + _tokenizer.NextToken(); + return retv; + } + + public void CheckEOF() + { + _tokenizer.Check(Token.EOF); + } + + public object Parse(Type type) + { + // Null? + if (_tokenizer.CurrentToken == Token.Literal && _tokenizer.LiteralKind == LiteralKind.Null) + { + _tokenizer.NextToken(); + return null; + } + + // Handle nullable types + var typeUnderlying = Nullable.GetUnderlyingType(type); + if (typeUnderlying != null) + type = typeUnderlying; + + // See if we have a reader + Func parser; + if (Reader._parsers.TryGetValue(type, out parser)) + { + return parser(this, type); + } + + // See if we have factory + Func factory; + if (Reader._typeFactories.TryGetValue(type, out factory)) + { + // Try first without passing dictionary keys + object into = factory(this, null); + if (into == null) + { + // This is a awkward situation. The factory requires a value from the dictionary + // in order to create the target object (typically an abstract class with the class + // kind recorded in the Json). Since there's no guarantee of order in a json dictionary + // we can't assume the required key is first. + // So, create a bookmark on the tokenizer, read keys until the factory returns an + // object instance and then rewind the tokenizer and continue + + // Create a bookmark so we can rewind + _tokenizer.CreateBookmark(); + + // Skip the opening brace + _tokenizer.Skip(Token.OpenBrace); + + // First pass to work out type + ParseDictionaryKeys(key => + { + // Try to instantiate the object + into = factory(this, key); + return into == null; + }); + + // Move back to start of the dictionary + _tokenizer.RewindToBookmark(); + + // Quit if still didn't get an object from the factory + if (into == null) + throw new InvalidOperationException("Factory didn't create object instance (probably due to a missing key in the Json)"); + } + + // Second pass + ParseInto(into); + + // Done + return into; + } + + // Do we already have an into parser? + Action intoParser; + if (Reader._intoParsers.TryGetValue(type, out intoParser)) + { + var into = DecoratingActivator.CreateInstance(type); + ParseInto(into); + return into; + } + + // Enumerated type? + if (type.IsEnum) + { + if (type.GetCustomAttributes(typeof(FlagsAttribute), false).Any()) + return ReadLiteral(literal => { + try + { + return Enum.Parse(type, (string)literal); + } + catch + { + return Enum.ToObject(type, literal); + } + }); + else + return ReadLiteral(literal => { + + try + { + return Enum.Parse(type, (string)literal); + } + catch (Exception) + { + var attr = type.GetCustomAttributes(typeof(JsonUnknownAttribute), false).FirstOrDefault(); + if (attr == null) + throw; + + return ((JsonUnknownAttribute)attr).UnknownValue; + } + + }); + } + + // Array? + if (type.IsArray && type.GetArrayRank() == 1) + { + // First parse as a List<> + var listType = typeof(List<>).MakeGenericType(type.GetElementType()); + var list = DecoratingActivator.CreateInstance(listType); + ParseInto(list); + + return listType.GetMethod("ToArray").Invoke(list, null); + } + + // Convert interfaces to concrete types + if (type.IsInterface) + type = Utils.ResolveInterfaceToClass(type); + + // Untyped dictionary? + if (_tokenizer.CurrentToken == Token.OpenBrace && (type.IsAssignableFrom(typeof(IDictionary)))) + { +#if !PETAJSON_NO_DYNAMIC + var container = (new ExpandoObject()) as IDictionary; +#else + var container = new Dictionary(); +#endif + ParseDictionary(key => + { + container[key] = Parse(typeof(Object)); + }); + + return container; + } + + // Untyped list? + if (_tokenizer.CurrentToken == Token.OpenSquare && (typeof(IList).IsAssignableFrom(type))) + { + var list = DecoratingActivator.CreateInstance(type); + ParseInto(list); + return type.GetMethod("ToArray").Invoke(list, null); + } + + // Untyped literal? + if (_tokenizer.CurrentToken == Token.Literal && type.IsAssignableFrom(_tokenizer.LiteralType)) + { + var lit = _tokenizer.LiteralValue; + _tokenizer.NextToken(); + return lit; + } + + // Call value type resolver + if (type.IsValueType) + { + var tp = _parsers.Get(type, () => _parserResolver(type)); + if (tp != null) + { + return tp(this, type); + } + } + + // Call reference type resolver + if (type.IsClass && type != typeof(object)) + { + var into = DecoratingActivator.CreateInstance(type); + ParseInto(into); + return into; + } + + // Give up + throw new InvalidDataException(string.Format("syntax error, unexpected token {0}", _tokenizer.CurrentToken)); + } + + // Parse into an existing object instance + public void ParseInto(object into) + { + if (into == null) + return; + + if (_tokenizer.CurrentToken == Token.Literal && _tokenizer.LiteralKind == LiteralKind.Null) + { + throw new InvalidOperationException("can't parse null into existing instance"); + //return; + } + + var type = into.GetType(); + + // Existing parse into handler? + Action parseInto; + if (_intoParsers.TryGetValue(type, out parseInto)) + { + parseInto(this, into); + return; + } + + // Generic dictionary? + var dictType = Utils.FindGenericInterface(type, typeof(IDictionary<,>)); + if (dictType != null) + { + // Get the key and value types + var typeKey = dictType.GetGenericArguments()[0]; + var typeValue = dictType.GetGenericArguments()[1]; + + // Parse it + IDictionary dict = (IDictionary)into; + dict.Clear(); + ParseDictionary(key => + { + dict.Add(Convert.ChangeType(key, typeKey), Parse(typeValue)); + }); + + return; + } + + // Generic list + var listType = Utils.FindGenericInterface(type, typeof(IList<>)); + if (listType != null) + { + // Get element type + var typeElement = listType.GetGenericArguments()[0]; + + // Parse it + IList list = (IList)into; + list.Clear(); + ParseArray(() => + { + list.Add(Parse(typeElement)); + }); + + return; + } + + // Untyped dictionary + var objDict = into as IDictionary; + if (objDict != null) + { + objDict.Clear(); + ParseDictionary(key => + { + objDict[key] = Parse(typeof(Object)); + }); + return; + } + + // Untyped list + var objList = into as IList; + if (objList != null) + { + objList.Clear(); + ParseArray(() => + { + objList.Add(Parse(typeof(Object))); + }); + return; + } + + // Try to resolve a parser + var intoParser = _intoParsers.Get(type, () => _intoParserResolver(type)); + if (intoParser != null) + { + intoParser(this, into); + return; + } + + throw new InvalidOperationException(string.Format("Don't know how to parse into type '{0}'", type.FullName)); + } + + public T Parse() + { + return (T)Parse(typeof(T)); + } + + public LiteralKind GetLiteralKind() + { + return _tokenizer.LiteralKind; + } + + public string GetLiteralString() + { + return _tokenizer.String; + } + + public void NextToken() + { + _tokenizer.NextToken(); + } + + // Parse a dictionary + public void ParseDictionary(Action callback) + { + _tokenizer.Skip(Token.OpenBrace); + ParseDictionaryKeys(key => { callback(key); return true; }); + _tokenizer.Skip(Token.CloseBrace); + } + + // Parse dictionary keys, calling callback for each one. Continues until end of input + // or when callback returns false + private void ParseDictionaryKeys(Func callback) + { + // End? + while (_tokenizer.CurrentToken != Token.CloseBrace) + { + // Parse the key + string key = null; + if (_tokenizer.CurrentToken == Token.Identifier && (_options & JsonOptions.StrictParser) == 0) + { + key = _tokenizer.String; + } + else if (_tokenizer.CurrentToken == Token.Literal && _tokenizer.LiteralKind == LiteralKind.String) + { + key = (string)_tokenizer.LiteralValue; + } + else + { + throw new InvalidDataException("syntax error, expected string literal or identifier"); + } + _tokenizer.NextToken(); + _tokenizer.Skip(Token.Colon); + + // Remember current position + var pos = _tokenizer.CurrentTokenPosition; + + // Call the callback, quit if cancelled + _contextStack.Add(key); + bool doDefaultProcessing = callback(key); + _contextStack.RemoveAt(_contextStack.Count - 1); + if (!doDefaultProcessing) + return; + + // If the callback didn't read anything from the tokenizer, then skip it ourself + if (pos.Line == _tokenizer.CurrentTokenPosition.Line && pos.Offset == _tokenizer.CurrentTokenPosition.Offset) + { + Parse(typeof(object)); + } + + // Separating/trailing comma + if (_tokenizer.SkipIf(Token.Comma)) + { + if ((_options & JsonOptions.StrictParser) != 0 && _tokenizer.CurrentToken == Token.CloseBrace) + { + throw new InvalidDataException("Trailing commas not allowed in strict mode"); + } + continue; + } + + // End + break; + } + } + + // Parse an array + public void ParseArray(Action callback) + { + _tokenizer.Skip(Token.OpenSquare); + + int index = 0; + while (_tokenizer.CurrentToken != Token.CloseSquare) + { + _contextStack.Add(string.Format("[{0}]", index)); + callback(); + _contextStack.RemoveAt(_contextStack.Count - 1); + + if (_tokenizer.SkipIf(Token.Comma)) + { + if ((_options & JsonOptions.StrictParser) != 0 && _tokenizer.CurrentToken == Token.CloseSquare) + { + throw new InvalidDataException("Trailing commas not allowed in strict mode"); + } + continue; + } + break; + } + + _tokenizer.Skip(Token.CloseSquare); + } + + // Yikes! + public static Func> _intoParserResolver; + public static Func> _parserResolver; + public static ThreadSafeCache> _parsers = new ThreadSafeCache>(); + public static ThreadSafeCache> _intoParsers = new ThreadSafeCache>(); + public static ThreadSafeCache> _typeFactories = new ThreadSafeCache>(); + } + + public class Writer : IJsonWriter + { + static Writer() + { + _formatterResolver = ResolveFormatter; + + // Register standard formatters + _formatters.Add(typeof(string), (w, o) => w.WriteStringLiteral((string)o)); + _formatters.Add(typeof(char), (w, o) => w.WriteStringLiteral(((char)o).ToString())); + _formatters.Add(typeof(bool), (w, o) => w.WriteRaw(((bool)o) ? "true" : "false")); + Action convertWriter = (w, o) => w.WriteRaw((string)Convert.ChangeType(o, typeof(string), System.Globalization.CultureInfo.InvariantCulture)); + _formatters.Add(typeof(int), convertWriter); + _formatters.Add(typeof(uint), convertWriter); + _formatters.Add(typeof(long), convertWriter); + _formatters.Add(typeof(ulong), convertWriter); + _formatters.Add(typeof(short), convertWriter); + _formatters.Add(typeof(ushort), convertWriter); + _formatters.Add(typeof(decimal), convertWriter); + _formatters.Add(typeof(byte), convertWriter); + _formatters.Add(typeof(sbyte), convertWriter); + _formatters.Add(typeof(DateTime), (w, o) => convertWriter(w, Utils.ToUnixMilliseconds((DateTime)o))); + _formatters.Add(typeof(float), (w, o) => w.WriteRaw(((float)o).ToString("R", System.Globalization.CultureInfo.InvariantCulture))); + _formatters.Add(typeof(double), (w, o) => w.WriteRaw(((double)o).ToString("R", System.Globalization.CultureInfo.InvariantCulture))); + _formatters.Add(typeof(byte[]), (w, o) => + { + w.WriteRaw("\""); + w.WriteRaw(Convert.ToBase64String((byte[])o)); + w.WriteRaw("\""); + }); + } + + public static Func> _formatterResolver; + public static Dictionary> _formatters = new Dictionary>(); + + static Action ResolveFormatter(Type type) + { + // Try `void FormatJson(IJsonWriter)` + var formatJson = ReflectionInfo.FindFormatJson(type); + if (formatJson != null) + { + if (formatJson.ReturnType == typeof(void)) + return (w, obj) => formatJson.Invoke(obj, new Object[] { w }); + if (formatJson.ReturnType == typeof(string)) + return (w, obj) => w.WriteStringLiteral((string)formatJson.Invoke(obj, new Object[] { })); + } + + var ri = ReflectionInfo.GetReflectionInfo(type); + if (ri != null) + return ri.Write; + else + return null; + } + + public Writer(TextWriter w, JsonOptions options) + { + _writer = w; + _needElementSeparator = false; + _options = options; + } + + private TextWriter _writer; + private bool _needElementSeparator = false; + private JsonOptions _options; + private char _currentBlockKind = '\0'; + + // Start the next element, writing separators and white space + void NextElement() + { + if (_needElementSeparator) + { + WriteRaw(","); + } + else + { + WriteRaw(_currentBlockKind.ToString()); + } + + _needElementSeparator = true; + } + + // Write next array element + public void WriteElement() + { + if (_currentBlockKind != '[') + throw new InvalidOperationException("Attempt to write array element when not in array block"); + NextElement(); + } + + // Write next dictionary key + public void WriteKey(string key) + { + if (_currentBlockKind != '{') + throw new InvalidOperationException("Attempt to write dictionary element when not in dictionary block"); + NextElement(); + WriteStringLiteral(key); + WriteRaw(((_options & JsonOptions.WriteWhitespace) != 0) ? ": " : ":"); + } + + // Write an already escaped dictionary key + public void WriteKeyNoEscaping(string key) + { + if (_currentBlockKind != '{') + throw new InvalidOperationException("Attempt to write dictionary element when not in dictionary block"); + NextElement(); + WriteRaw("\""); + WriteRaw(key); + WriteRaw("\""); + WriteRaw(((_options & JsonOptions.WriteWhitespace) != 0) ? ": " : ":"); + } + + // Write anything + public void WriteRaw(string str) + { + _writer.Write(str); + } + + static int IndexOfEscapeableChar(string str, int pos) + { + int length = str.Length; + while (pos < length) + { + var ch = str[pos]; + if (ch == '\\' || ch == '/' || ch == '\"' || (ch >= 0 && ch <= 0x1f) || (ch >= 0x7f && ch <= 0x9f) || ch == 0x2028 || ch == 0x2029) + return pos; + pos++; + } + + return -1; + } + + public void WriteStringLiteral(string str) + { + if (str == null) + { + _writer.Write("null"); + return; + } + _writer.Write("\""); + + int pos = 0; + int escapePos; + while ((escapePos = IndexOfEscapeableChar(str, pos)) >= 0) + { + if (escapePos > pos) + _writer.Write(str.Substring(pos, escapePos - pos)); + + switch (str[escapePos]) + { + case '\"': _writer.Write("\\\""); break; + case '\\': _writer.Write("\\\\"); break; + case '/': _writer.Write("\\/"); break; + case '\b': _writer.Write("\\b"); break; + case '\f': _writer.Write("\\f"); break; + case '\n': _writer.Write("\\n"); break; + case '\r': _writer.Write("\\r"); break; + case '\t': _writer.Write("\\t"); break; + default: + _writer.Write(string.Format("\\u{0:x4}", (int)str[escapePos])); + break; + } + + pos = escapePos + 1; + } + + + if (str.Length > pos) + _writer.Write(str.Substring(pos)); + _writer.Write("\""); + } + + // Write an array or dictionary block + private void WriteBlock(string open, string close, Action callback) + { + var prevBlockKind = _currentBlockKind; + _currentBlockKind = open[0]; + + var didNeedElementSeparator = _needElementSeparator; + _needElementSeparator = false; + + callback(); + + if (!_needElementSeparator) + { + WriteRaw(open); + } + WriteRaw(close); + + _needElementSeparator = didNeedElementSeparator; + _currentBlockKind = prevBlockKind; + } + + // Write an array + public void WriteArray(Action callback) + { + WriteBlock("[", "]", callback); + } + + // Write a dictionary + public void WriteDictionary(Action callback) + { + WriteBlock("{", "}", callback); + } + + // Write any value + public void WriteValue(object value) + { + // Special handling for null + if (value == null) + { + _writer.Write("null"); + return; + } + + var type = value.GetType(); + + // Handle nullable types + var typeUnderlying = Nullable.GetUnderlyingType(type); + if (typeUnderlying != null) + type = typeUnderlying; + + // Look up type writer + Action typeWriter; + if (_formatters.TryGetValue(type, out typeWriter)) + { + // Write it + typeWriter(this, value); + return; + } + + // Enumerated type? + if (type.IsEnum) + { + if (type.GetCustomAttributes(typeof(FlagsAttribute), false).Any()) + WriteRaw(Convert.ToUInt32(value).ToString(CultureInfo.InvariantCulture)); + else + WriteStringLiteral(value.ToString()); + return; + } + + // Dictionary? + var d = value as System.Collections.IDictionary; + if (d != null) + { + WriteDictionary(() => + { + foreach (var key in d.Keys) + { + WriteKey(key.ToString()); + WriteValue(d[key]); + } + }); + return; + } + + // Dictionary? + var dso = value as IDictionary; + if (dso != null) + { + WriteDictionary(() => + { + foreach (var key in dso.Keys) + { + WriteKey(key.ToString()); + WriteValue(dso[key]); + } + }); + return; + } + + // Array? + var e = value as System.Collections.IEnumerable; + if (e != null) + { + WriteArray(() => + { + foreach (var i in e) + { + WriteElement(); + WriteValue(i); + } + }); + return; + } + + // Resolve a formatter + var formatter = _formatterResolver(type); + if (formatter != null) + { + _formatters[type] = formatter; + formatter(this, value); + return; + } + + // Give up + throw new InvalidDataException(string.Format("Don't know how to write '{0}' to json", value.GetType())); + } + } + + // Information about a field or property found through reflection + public class JsonMemberInfo + { + // The Json key for this member + public string JsonKey; + + // True if should keep existing instance (reference types only) + public bool KeepInstance; + + // True if deprecated + public bool Deprecated; + + + + // Reflected member info + MemberInfo _mi; + public MemberInfo Member + { + get { return _mi; } + set + { + // Store it + _mi = value; + + // Also create getters and setters + if (_mi is PropertyInfo) + { + GetValue = (obj) => ((PropertyInfo)_mi).GetValue(obj, null); + SetValue = (obj, val) => ((PropertyInfo)_mi).SetValue(obj, val, null); + } + else + { + GetValue = ((FieldInfo)_mi).GetValue; + SetValue = ((FieldInfo)_mi).SetValue; + } + } + } + + // Member type + public Type MemberType + { + get + { + if (Member is PropertyInfo) + { + return ((PropertyInfo)Member).PropertyType; + } + else + { + return ((FieldInfo)Member).FieldType; + } + } + } + + // Get/set helpers + public Action SetValue; + public Func GetValue; + } + + // Stores reflection info about a type + public class ReflectionInfo + { + // List of members to be serialized + public List Members; + + // Cache of these ReflectionInfos's + static ThreadSafeCache _cache = new ThreadSafeCache(); + + public static MethodInfo FindFormatJson(Type type) + { + if (type.IsValueType) + { + // Try `void FormatJson(IJsonWriter)` + var formatJson = type.GetMethod("FormatJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(IJsonWriter) }, null); + if (formatJson != null && formatJson.ReturnType == typeof(void)) + return formatJson; + + // Try `string FormatJson()` + formatJson = type.GetMethod("FormatJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null); + if (formatJson != null && formatJson.ReturnType == typeof(string)) + return formatJson; + } + return null; + } + + public static MethodInfo FindParseJson(Type type) + { + // Try `T ParseJson(IJsonReader)` + var parseJson = type.GetMethod("ParseJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(IJsonReader) }, null); + if (parseJson != null && parseJson.ReturnType == type) + return parseJson; + + // Try `T ParseJson(string)` + parseJson = type.GetMethod("ParseJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null); + if (parseJson != null && parseJson.ReturnType == type) + return parseJson; + + return null; + } + + public static object GetDefault(Type type) + { + if (type.IsValueType) + { + return Activator.CreateInstance(type); + } + return null; + } + // Write one of these types + public void Write(IJsonWriter w, object val) + { + w.WriteDictionary(() => + { + var writing = val as IJsonWriting; + if (writing != null) + writing.OnJsonWriting(w); + + foreach (var jmi in Members.Where(x => !x.Deprecated )) + { + var attr = jmi.Member.GetCustomAttributes( + typeof(DataMemberAttribute), false + ).OfType().FirstOrDefault(); + if (attr.EmitDefaultValue) + { + w.WriteKeyNoEscaping(jmi.JsonKey); + w.WriteValue(jmi.GetValue(val)); + } + else + { + var ttype = val.GetType(); + if (jmi.GetValue(val) != GetDefault(ttype)) + { + w.WriteKeyNoEscaping(jmi.JsonKey); + w.WriteValue(jmi.GetValue(val)); + } + } + } + + var written = val as IJsonWritten; + if (written != null) + written.OnJsonWritten(w); + }); + } + + // Read one of these types. + // NB: Although PetaJson.JsonParseInto only works on reference type, when using reflection + // it also works for value types so we use the one method for both + public void ParseInto(IJsonReader r, object into) + { + var loading = into as IJsonLoading; + if (loading != null) + loading.OnJsonLoading(r); + + r.ParseDictionary(key => + { + ParseFieldOrProperty(r, into, key); + }); + + var loaded = into as IJsonLoaded; + if (loaded != null) + loaded.OnJsonLoaded(r); + } + + // The member info is stored in a list (as opposed to a dictionary) so that + // the json is written in the same order as the fields/properties are defined + // On loading, we assume the fields will be in the same order, but need to + // handle if they're not. This function performs a linear search, but + // starts after the last found item as an optimization that should work + // most of the time. + int _lastFoundIndex = 0; + bool FindMemberInfo(string name, out JsonMemberInfo found) + { + for (int i = 0; i < Members.Count; i++) + { + int index = (i + _lastFoundIndex) % Members.Count; + var jmi = Members[index]; + if (jmi.JsonKey == name) + { + _lastFoundIndex = index; + found = jmi; + return true; + } + } + found = null; + return false; + } + + // Parse a value from IJsonReader into an object instance + public void ParseFieldOrProperty(IJsonReader r, object into, string key) + { + // IJsonLoadField + var lf = into as IJsonLoadField; + if (lf != null && lf.OnJsonField(r, key)) + return; + + // Find member + JsonMemberInfo jmi; + if (FindMemberInfo(key, out jmi)) + { + // Try to keep existing instance + if (jmi.KeepInstance) + { + var subInto = jmi.GetValue(into); + if (subInto != null) + { + r.ParseInto(subInto); + return; + } + } + + // Parse and set + var val = r.Parse(jmi.MemberType); + jmi.SetValue(into, val); + return; + } + } + + // Get the reflection info for a specified type + public static ReflectionInfo GetReflectionInfo(Type type) + { + // Check cache + return _cache.Get(type, () => + { + var allMembers = Utils.GetAllFieldsAndProperties(type); + + // Does type have a [Json] attribute + bool typeMarked = type.GetCustomAttributes(typeof(JsonAttribute), true).OfType().Any(); + + // Do any members have a [Json] attribute + bool anyFieldsMarked = allMembers.Any(x => x.GetCustomAttributes(typeof(JsonAttribute), false).OfType().Any()); + +#if !PETAJSON_NO_DATACONTRACT + // Try with DataContract and friends + if (!typeMarked && !anyFieldsMarked && type.GetCustomAttributes(typeof(DataContractAttribute), true).OfType().Any()) + { + var ri = CreateReflectionInfo(type, mi => + { + // Get attributes + var attr = mi.GetCustomAttributes(typeof(DataMemberAttribute), false).OfType().FirstOrDefault(); + if (attr != null) + { + return new JsonMemberInfo() + { + Member = mi, + JsonKey = attr.Name ?? mi.Name, // No lower case first letter if using DataContract/Member + }; + } + + return null; + }); + + ri.Members.Sort((a, b) => String.CompareOrdinal(a.JsonKey, b.JsonKey)); // Match DataContractJsonSerializer + return ri; + } +#endif + { + // Should we serialize all public methods? + bool serializeAllPublics = typeMarked || !anyFieldsMarked; + + // Build + var ri = CreateReflectionInfo(type, mi => + { + // Explicitly excluded? + if (mi.GetCustomAttributes(typeof(JsonExcludeAttribute), false).Any()) + return null; + + // Get attributes + var attr = mi.GetCustomAttributes(typeof(JsonAttribute), false).OfType().FirstOrDefault(); + if (attr != null) + { + return new JsonMemberInfo() + { + Member = mi, + JsonKey = attr.Key ?? mi.Name.Substring(0, 1).ToLower() + mi.Name.Substring(1), + KeepInstance = attr.KeepInstance, + Deprecated = attr.Deprecated, + }; + } + + // Serialize all publics? + if (serializeAllPublics && Utils.IsPublic(mi)) + { + return new JsonMemberInfo() + { + Member = mi, + JsonKey = mi.Name.Substring(0, 1).ToLower() + mi.Name.Substring(1), + }; + } + + return null; + }); + return ri; + } + }); + } + + public static ReflectionInfo CreateReflectionInfo(Type type, Func callback) + { + // Work out properties and fields + var members = Utils.GetAllFieldsAndProperties(type).Select(x => callback(x)).Where(x => x != null).ToList(); + + // Anything with KeepInstance must be a reference type + var invalid = members.FirstOrDefault(x => x.KeepInstance && x.MemberType.IsValueType); + if (invalid != null) + { + throw new InvalidOperationException(string.Format("KeepInstance=true can only be applied to reference types ({0}.{1})", type.FullName, invalid.Member)); + } + + // Must have some members + if (!members.Any()) + return null; + + // Create reflection info + return new ReflectionInfo() { Members = members }; + } + } + + public class ThreadSafeCache + { + public ThreadSafeCache() + { + + } + + public TValue Get(TKey key, Func createIt) + { + // Check if already exists + _lock.EnterReadLock(); + try + { + TValue val; + if (_map.TryGetValue(key, out val)) + return val; + } + finally + { + _lock.ExitReadLock(); + } + + // Nope, take lock and try again + _lock.EnterWriteLock(); + try + { + // Check again before creating it + TValue val; + if (!_map.TryGetValue(key, out val)) + { + // Store the new one + val = createIt(); + _map[key] = val; + } + return val; + } + finally + { + _lock.ExitWriteLock(); + } + } + + public bool TryGetValue(TKey key, out TValue val) + { + _lock.EnterReadLock(); + try + { + return _map.TryGetValue(key, out val); + } + finally + { + _lock.ExitReadLock(); + } + } + + public void Set(TKey key, TValue value) + { + _lock.EnterWriteLock(); + try + { + _map[key] = value; + } + finally + { + _lock.ExitWriteLock(); + } + } + + Dictionary _map = new Dictionary(); + ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + } + + internal static class Utils + { + // Get all fields and properties of a type + public static IEnumerable GetAllFieldsAndProperties(Type t) + { + if (t == null) + return Enumerable.Empty(); + + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + return t.GetMembers(flags).Where(x => x is FieldInfo || x is PropertyInfo).Concat(GetAllFieldsAndProperties(t.BaseType)); + } + + public static Type FindGenericInterface(Type type, Type tItf) + { + foreach (var t in type.GetInterfaces()) + { + // Is this a generic list? + if (t.IsGenericType && t.GetGenericTypeDefinition() == tItf) + return t; + } + + return null; + } + + public static bool IsPublic(MemberInfo mi) + { + // Public field + var fi = mi as FieldInfo; + if (fi != null) + return fi.IsPublic; + + // Public property + // (We only check the get method so we can work with anonymous types) + var pi = mi as PropertyInfo; + if (pi != null) + { + var gm = pi.GetGetMethod(true); + return (gm != null && gm.IsPublic); + } + + return false; + } + + public static Type ResolveInterfaceToClass(Type tItf) + { + // Generic type + if (tItf.IsGenericType) + { + var genDef = tItf.GetGenericTypeDefinition(); + + // IList<> -> List<> + if (genDef == typeof(IList<>)) + { + return typeof(List<>).MakeGenericType(tItf.GetGenericArguments()); + } + + // IDictionary -> Dictionary + if (genDef == typeof(IDictionary<,>) && tItf.GetGenericArguments()[0] == typeof(string)) + { + return typeof(Dictionary<,>).MakeGenericType(tItf.GetGenericArguments()); + } + } + + // IEnumerable -> List<> + if (typeof(IEnumerable).IsAssignableFrom(tItf)) + return typeof(List<>).MakeGenericType(tItf.GetGenericArguments()); + + // IDicitonary -> Dictionary + if (tItf == typeof(IDictionary)) + return typeof(Dictionary); + return tItf; + } + + public static long ToUnixMilliseconds(DateTime This) + { + return (long)This.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; + } + + public static DateTime FromUnixMilliseconds(long timeStamp) + { + return new DateTime(1970, 1, 1).AddMilliseconds(timeStamp); + } + + } + + public class Tokenizer + { + public Tokenizer(TextReader r, JsonOptions options) + { + _underlying = r; + _options = options; + FillBuffer(); + NextChar(); + NextToken(); + } + + private JsonOptions _options; + private StringBuilder _sb = new StringBuilder(); + private TextReader _underlying; + private char[] _buf = new char[4096]; + private int _pos; + private int _bufUsed; + private StringBuilder _rewindBuffer; + private int _rewindBufferPos; + private JsonLineOffset _currentCharPos; + private char _currentChar; + private Stack _bookmarks = new Stack(); + + public JsonLineOffset CurrentTokenPosition; + public Token CurrentToken; + public LiteralKind LiteralKind; + public string String; + + public object LiteralValue + { + get + { + if (CurrentToken != Token.Literal) + throw new InvalidOperationException("token is not a literal"); + switch (LiteralKind) + { + case LiteralKind.Null: return null; + case LiteralKind.False: return false; + case LiteralKind.True: return true; + case LiteralKind.String: return String; + case LiteralKind.SignedInteger: return long.Parse(String, CultureInfo.InvariantCulture); + case LiteralKind.UnsignedInteger: + if (String.StartsWith("0x") || String.StartsWith("0X")) + return Convert.ToUInt64(String.Substring(2), 16); + else + return ulong.Parse(String, CultureInfo.InvariantCulture); + case LiteralKind.FloatingPoint: return double.Parse(String, CultureInfo.InvariantCulture); + } + return null; + } + } + + public Type LiteralType + { + get + { + if (CurrentToken != Token.Literal) + throw new InvalidOperationException("token is not a literal"); + switch (LiteralKind) + { + case LiteralKind.Null: return typeof(Object); + case LiteralKind.False: return typeof(Boolean); + case LiteralKind.True: return typeof(Boolean); + case LiteralKind.String: return typeof(string); + case LiteralKind.SignedInteger: return typeof(long); + case LiteralKind.UnsignedInteger: return typeof(ulong); + case LiteralKind.FloatingPoint: return typeof(double); + } + + return null; + } + } + + // This object represents the entire state of the reader and is used for rewind + struct ReaderState + { + public ReaderState(Tokenizer tokenizer) + { + _currentCharPos = tokenizer._currentCharPos; + _currentChar = tokenizer._currentChar; + _string = tokenizer.String; + _literalKind = tokenizer.LiteralKind; + _rewindBufferPos = tokenizer._rewindBufferPos; + _currentTokenPos = tokenizer.CurrentTokenPosition; + _currentToken = tokenizer.CurrentToken; + } + + public void Apply(Tokenizer tokenizer) + { + tokenizer._currentCharPos = _currentCharPos; + tokenizer._currentChar = _currentChar; + tokenizer._rewindBufferPos = _rewindBufferPos; + tokenizer.CurrentToken = _currentToken; + tokenizer.CurrentTokenPosition = _currentTokenPos; + tokenizer.String = _string; + tokenizer.LiteralKind = _literalKind; + } + + private JsonLineOffset _currentCharPos; + private JsonLineOffset _currentTokenPos; + private char _currentChar; + private Token _currentToken; + private LiteralKind _literalKind; + private string _string; + private int _rewindBufferPos; + } + + // Create a rewind bookmark + public void CreateBookmark() + { + _bookmarks.Push(new ReaderState(this)); + if (_rewindBuffer == null) + { + _rewindBuffer = new StringBuilder(); + _rewindBufferPos = 0; + } + } + + // Discard bookmark + public void DiscardBookmark() + { + _bookmarks.Pop(); + if (_bookmarks.Count == 0) + { + _rewindBuffer = null; + _rewindBufferPos = 0; + } + } + + // Rewind to a bookmark + public void RewindToBookmark() + { + _bookmarks.Pop().Apply(this); + } + + // Fill buffer by reading from underlying TextReader + void FillBuffer() + { + _bufUsed = _underlying.Read(_buf, 0, _buf.Length); + _pos = 0; + } + + // Get the next character from the input stream + // (this function could be extracted into a few different methods, but is mostly inlined + // for performance - yes it makes a difference) + public char NextChar() + { + if (_rewindBuffer == null) + { + if (_pos >= _bufUsed) + { + if (_bufUsed > 0) + { + FillBuffer(); + } + if (_bufUsed == 0) + { + return _currentChar = '\0'; + } + } + + // Next + _currentCharPos.Offset++; + return _currentChar = _buf[_pos++]; + } + + if (_rewindBufferPos < _rewindBuffer.Length) + { + _currentCharPos.Offset++; + return _currentChar = _rewindBuffer[_rewindBufferPos++]; + } + else + { + if (_pos >= _bufUsed && _bufUsed > 0) + FillBuffer(); + + _currentChar = _bufUsed == 0 ? '\0' : _buf[_pos++]; + _rewindBuffer.Append(_currentChar); + _rewindBufferPos++; + _currentCharPos.Offset++; + return _currentChar; + } + } + + // Read the next token from the input stream + // (Mostly inline for performance) + public void NextToken() + { + while (true) + { + // Skip whitespace and handle line numbers + while (true) + { + if (_currentChar == '\r') + { + if (NextChar() == '\n') + { + NextChar(); + } + _currentCharPos.Line++; + _currentCharPos.Offset = 0; + } + else if (_currentChar == '\n') + { + if (NextChar() == '\r') + { + NextChar(); + } + _currentCharPos.Line++; + _currentCharPos.Offset = 0; + } + else if (_currentChar == ' ') + { + NextChar(); + } + else if (_currentChar == '\t') + { + NextChar(); + } + else + break; + } + + // Remember position of token + CurrentTokenPosition = _currentCharPos; + + // Handle common characters first + switch (_currentChar) + { + case '/': + // Comments not support in strict mode + if ((_options & JsonOptions.StrictParser) != 0) + { + throw new InvalidDataException(string.Format("syntax error, unexpected character '{0}'", _currentChar)); + } + + // Process comment + NextChar(); + switch (_currentChar) + { + case '/': + NextChar(); + while (_currentChar != '\0' && _currentChar != '\r' && _currentChar != '\n') + { + NextChar(); + } + break; + + case '*': + bool endFound = false; + while (!endFound && _currentChar != '\0') + { + if (_currentChar == '*') + { + NextChar(); + if (_currentChar == '/') + { + endFound = true; + } + } + NextChar(); + } + break; + + default: + throw new InvalidDataException("syntax error, unexpected character after slash"); + } + continue; + + case '\"': + case '\'': + { + _sb.Length = 0; + var quoteKind = _currentChar; + NextChar(); + while (_currentChar != '\0') + { + if (_currentChar == '\\') + { + NextChar(); + var escape = _currentChar; + switch (escape) + { + case '\"': _sb.Append('\"'); break; + case '\\': _sb.Append('\\'); break; + case '/': _sb.Append('/'); break; + case 'b': _sb.Append('\b'); break; + case 'f': _sb.Append('\f'); break; + case 'n': _sb.Append('\n'); break; + case 'r': _sb.Append('\r'); break; + case 't': _sb.Append('\t'); break; + case 'u': + var sbHex = new StringBuilder(); + for (int i = 0; i < 4; i++) + { + NextChar(); + sbHex.Append(_currentChar); + } + _sb.Append((char)Convert.ToUInt16(sbHex.ToString(), 16)); + break; + + default: + throw new InvalidDataException(string.Format("Invalid escape sequence in string literal: '\\{0}'", _currentChar)); + } + } + else if (_currentChar == quoteKind) + { + String = _sb.ToString(); + CurrentToken = Token.Literal; + LiteralKind = LiteralKind.String; + NextChar(); + return; + } + else + { + _sb.Append(_currentChar); + } + + NextChar(); + } + throw new InvalidDataException("syntax error, unterminated string literal"); + } + + case '{': CurrentToken = Token.OpenBrace; NextChar(); return; + case '}': CurrentToken = Token.CloseBrace; NextChar(); return; + case '[': CurrentToken = Token.OpenSquare; NextChar(); return; + case ']': CurrentToken = Token.CloseSquare; NextChar(); return; + case '=': CurrentToken = Token.Equal; NextChar(); return; + case ':': CurrentToken = Token.Colon; NextChar(); return; + case ';': CurrentToken = Token.SemiColon; NextChar(); return; + case ',': CurrentToken = Token.Comma; NextChar(); return; + case '\0': CurrentToken = Token.EOF; return; + } + + // Number? + if (char.IsDigit(_currentChar) || _currentChar == '-') + { + TokenizeNumber(); + return; + } + + // Identifier? (checked for after everything else as identifiers are actually quite rare in valid json) + if (Char.IsLetter(_currentChar) || _currentChar == '_' || _currentChar == '$') + { + // Find end of identifier + _sb.Length = 0; + while (Char.IsLetterOrDigit(_currentChar) || _currentChar == '_' || _currentChar == '$') + { + _sb.Append(_currentChar); + NextChar(); + } + String = _sb.ToString(); + + // Handle special identifiers + switch (String) + { + case "true": + LiteralKind = LiteralKind.True; + CurrentToken = Token.Literal; + return; + + case "false": + LiteralKind = LiteralKind.False; + CurrentToken = Token.Literal; + return; + + case "null": + LiteralKind = LiteralKind.Null; + CurrentToken = Token.Literal; + return; + } + + CurrentToken = Token.Identifier; + return; + } + + // What the? + throw new InvalidDataException(string.Format("syntax error, unexpected character '{0}'", _currentChar)); + } + } + + // Parse a sequence of characters that could make up a valid number + // For performance, we don't actually parse it into a number yet. When using PetaJsonEmit we parse + // later, directly into a value type to avoid boxing + private void TokenizeNumber() + { + _sb.Length = 0; + + // Leading negative sign + bool signed = false; + if (_currentChar == '-') + { + signed = true; + _sb.Append(_currentChar); + NextChar(); + } + + // Hex prefix? + bool hex = false; + if (_currentChar == '0' && (_options & JsonOptions.StrictParser) == 0) + { + _sb.Append(_currentChar); + NextChar(); + if (_currentChar == 'x' || _currentChar == 'X') + { + _sb.Append(_currentChar); + NextChar(); + hex = true; + } + } + + // Process characters, but vaguely figure out what type it is + bool cont = true; + bool fp = false; + while (cont) + { + switch (_currentChar) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + _sb.Append(_currentChar); + NextChar(); + break; + + case 'A': + case 'a': + case 'B': + case 'b': + case 'C': + case 'c': + case 'D': + case 'd': + case 'F': + case 'f': + if (!hex) + cont = false; + else + { + _sb.Append(_currentChar); + NextChar(); + } + break; + + case '.': + if (hex) + { + cont = false; + } + else + { + fp = true; + _sb.Append(_currentChar); + NextChar(); + } + break; + + case 'E': + case 'e': + if (!hex) + { + fp = true; + _sb.Append(_currentChar); + NextChar(); + if (_currentChar == '+' || _currentChar == '-') + { + _sb.Append(_currentChar); + NextChar(); + } + } + break; + + default: + cont = false; + break; + } + } + + if (char.IsLetter(_currentChar)) + throw new InvalidDataException(string.Format("syntax error, invalid character following number '{0}'", _sb.ToString())); + + // Setup token + String = _sb.ToString(); + CurrentToken = Token.Literal; + + // Setup literal kind + if (fp) + { + LiteralKind = LiteralKind.FloatingPoint; + } + else if (signed) + { + LiteralKind = LiteralKind.SignedInteger; + } + else + { + LiteralKind = LiteralKind.UnsignedInteger; + } + } + + // Check the current token, throw exception if mismatch + public void Check(Token tokenRequired) + { + if (tokenRequired != CurrentToken) + { + throw new InvalidDataException(string.Format("syntax error, expected {0} found {1}", tokenRequired, CurrentToken)); + } + } + + // Skip token which must match + public void Skip(Token tokenRequired) + { + Check(tokenRequired); + NextToken(); + } + + // Skip token if it matches + public bool SkipIf(Token tokenRequired) + { + if (tokenRequired == CurrentToken) + { + NextToken(); + return true; + } + return false; + } + } + +#if !PETAJSON_NO_EMIT + static class Emit + { + + // Generates a function that when passed an object of specified type, renders it to an IJsonReader + public static Action MakeFormatter(Type type) + { + var formatJson = ReflectionInfo.FindFormatJson(type); + if (formatJson != null) + { + var method = new DynamicMethod("invoke_formatJson", null, new Type[] { typeof(IJsonWriter), typeof(Object) }, true); + var il = method.GetILGenerator(); + if (formatJson.ReturnType == typeof(string)) + { + // w.WriteStringLiteral(o.FormatJson()) + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Unbox, type); + il.Emit(OpCodes.Call, formatJson); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral")); + } + else + { + // o.FormatJson(w); + il.Emit(OpCodes.Ldarg_1); + il.Emit(type.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, type); + il.Emit(OpCodes.Ldarg_0); + il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, formatJson); + } + il.Emit(OpCodes.Ret); + return (Action)method.CreateDelegate(typeof(Action)); + } + else + { + // Get the reflection info for this type + var ri = ReflectionInfo.GetReflectionInfo(type); + if (ri == null) + return null; + + // Create a dynamic method that can do the work + var method = new DynamicMethod("dynamic_formatter", null, new Type[] { typeof(IJsonWriter), typeof(object) }, true); + var il = method.GetILGenerator(); + + // Cast/unbox the target object and store in local variable + var locTypedObj = il.DeclareLocal(type); + il.Emit(OpCodes.Ldarg_1); + il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); + il.Emit(OpCodes.Stloc, locTypedObj); + + // Get Invariant CultureInfo (since we'll probably be needing this) + var locInvariant = il.DeclareLocal(typeof(IFormatProvider)); + il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod()); + il.Emit(OpCodes.Stloc, locInvariant); + + // These are the types we'll call .ToString(Culture.InvariantCulture) on + var toStringTypes = new Type[] { + typeof(int), typeof(uint), typeof(long), typeof(ulong), + typeof(short), typeof(ushort), typeof(decimal), + typeof(byte), typeof(sbyte) + }; + + // Theses types we also generate for + var otherSupportedTypes = new Type[] { + typeof(double), typeof(float), typeof(string), typeof(char) + }; + + // Call IJsonWriting if implemented + if (typeof(IJsonWriting).IsAssignableFrom(type)) + { + if (type.IsValueType) + { + il.Emit(OpCodes.Ldloca, locTypedObj); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWriting)).TargetMethods[0]); + } + else + { + il.Emit(OpCodes.Ldloc, locTypedObj); + il.Emit(OpCodes.Castclass, typeof(IJsonWriting)); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWriting", new Type[] { typeof(IJsonWriter) })); + } + } + + // Process all members + foreach (var m in ri.Members) + { + // Dont save deprecated properties + if (m.Deprecated) + { + continue; + } + + // Ignore write only properties + var pi = m.Member as PropertyInfo; + if (pi != null && pi.GetGetMethod(true) == null) + { + continue; + } + + // Write the Json key + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, m.JsonKey); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) })); + + // Load the writer + il.Emit(OpCodes.Ldarg_0); + + // Get the member type + var memberType = m.MemberType; + + // Load the target object + if (type.IsValueType) + { + il.Emit(OpCodes.Ldloca, locTypedObj); + } + else + { + il.Emit(OpCodes.Ldloc, locTypedObj); + } + + // Work out if we need the value or it's address on the stack + bool NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType))); + if (Nullable.GetUnderlyingType(memberType) != null) + { + NeedValueAddress = true; + } + + // Property? + if (pi != null) + { + // Call property's get method + if (type.IsValueType) + il.Emit(OpCodes.Call, pi.GetGetMethod(true)); + else + il.Emit(OpCodes.Callvirt, pi.GetGetMethod(true)); + + // If we need the address then store in a local and take it's address + if (NeedValueAddress) + { + var locTemp = il.DeclareLocal(memberType); + il.Emit(OpCodes.Stloc, locTemp); + il.Emit(OpCodes.Ldloca, locTemp); + } + } + + // Field? + var fi = m.Member as FieldInfo; + if (fi != null) + { + if (NeedValueAddress) + { + il.Emit(OpCodes.Ldflda, fi); + } + else + { + il.Emit(OpCodes.Ldfld, fi); + } + } + + Label? lblFinished = null; + + // Is it a nullable type? + var typeUnderlying = Nullable.GetUnderlyingType(memberType); + if (typeUnderlying != null) + { + // Duplicate the address so we can call get_HasValue() and then get_Value() + il.Emit(OpCodes.Dup); + + // Define some labels + var lblHasValue = il.DefineLabel(); + lblFinished = il.DefineLabel(); + + // Call has_Value + il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod()); + il.Emit(OpCodes.Brtrue, lblHasValue); + + // No value, write "null: + il.Emit(OpCodes.Pop); + il.Emit(OpCodes.Ldstr, "null"); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) })); + il.Emit(OpCodes.Br_S, lblFinished.Value); + + // Get it's value + il.MarkLabel(lblHasValue); + il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod()); + + // Switch to the underlying type from here on + memberType = typeUnderlying; + NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType))); + + // Work out again if we need the address of the value + if (NeedValueAddress) + { + var locTemp = il.DeclareLocal(memberType); + il.Emit(OpCodes.Stloc, locTemp); + il.Emit(OpCodes.Ldloca, locTemp); + } + } + + // ToString() + if (toStringTypes.Contains(memberType)) + { + // Convert to string + il.Emit(OpCodes.Ldloc, locInvariant); + il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(IFormatProvider) })); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) })); + } + + // ToString("R") + else if (memberType == typeof(float) || memberType == typeof(double)) + { + il.Emit(OpCodes.Ldstr, "R"); + il.Emit(OpCodes.Ldloc, locInvariant); + il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(string), typeof(IFormatProvider) })); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) })); + } + + // String? + else if (memberType == typeof(string)) + { + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) })); + } + + // Char? + else if (memberType == typeof(char)) + { + il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { })); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) })); + } + + // Bool? + else if (memberType == typeof(bool)) + { + var lblTrue = il.DefineLabel(); + var lblCont = il.DefineLabel(); + il.Emit(OpCodes.Brtrue_S, lblTrue); + il.Emit(OpCodes.Ldstr, "false"); + il.Emit(OpCodes.Br_S, lblCont); + il.MarkLabel(lblTrue); + il.Emit(OpCodes.Ldstr, "true"); + il.MarkLabel(lblCont); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) })); + } + + // NB: We don't support DateTime as it's format can be changed + + else + { + // Unsupported type, pass through + if (memberType.IsValueType) + { + il.Emit(OpCodes.Box, memberType); + } + il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) })); + } + + if (lblFinished.HasValue) + il.MarkLabel(lblFinished.Value); + } + + // Call IJsonWritten + if (typeof(IJsonWritten).IsAssignableFrom(type)) + { + if (type.IsValueType) + { + il.Emit(OpCodes.Ldloca, locTypedObj); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWritten)).TargetMethods[0]); + } + else + { + il.Emit(OpCodes.Ldloc, locTypedObj); + il.Emit(OpCodes.Castclass, typeof(IJsonWriting)); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWritten", new Type[] { typeof(IJsonWriter) })); + } + } + + // Done! + il.Emit(OpCodes.Ret); + var impl = (Action)method.CreateDelegate(typeof(Action)); + + // Wrap it in a call to WriteDictionary + return (w, obj) => + { + w.WriteDictionary(() => + { + impl(w, obj); + }); + }; + } + } + + // Pseudo box lets us pass a value type by reference. Used during + // deserialization of value types. + interface IPseudoBox + { + object GetValue(); + } + [Obfuscation(Exclude = true, ApplyToMembers = true)] + class PseudoBox : IPseudoBox where T : struct + { + public T value = default(T); + object IPseudoBox.GetValue() { return value; } + } + + + // Make a parser for value types + public static Func MakeParser(Type type) + { + System.Diagnostics.Debug.Assert(type.IsValueType); + + // ParseJson method? + var parseJson = ReflectionInfo.FindParseJson(type); + if (parseJson != null) + { + if (parseJson.GetParameters()[0].ParameterType == typeof(IJsonReader)) + { + var method = new DynamicMethod("invoke_ParseJson", typeof(Object), new Type[] { typeof(IJsonReader), typeof(Type) }, true); + var il = method.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, parseJson); + il.Emit(OpCodes.Box, type); + il.Emit(OpCodes.Ret); + return (Func)method.CreateDelegate(typeof(Func)); + } + else + { + var method = new DynamicMethod("invoke_ParseJson", typeof(Object), new Type[] { typeof(string) }, true); + var il = method.GetILGenerator(); + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, parseJson); + il.Emit(OpCodes.Box, type); + il.Emit(OpCodes.Ret); + var invoke = (Func)method.CreateDelegate(typeof(Func)); + + return (r, t) => + { + if (r.GetLiteralKind() == LiteralKind.String) + { + var o = invoke(r.GetLiteralString()); + r.NextToken(); + return o; + } + throw new InvalidDataException(string.Format("Expected string literal for type {0}", type.FullName)); + }; + } + } + else + { + // Get the reflection info for this type + var ri = ReflectionInfo.GetReflectionInfo(type); + if (ri == null) + return null; + + // We'll create setters for each property/field + var setters = new Dictionary>(); + + // Store the value in a pseudo box until it's fully initialized + var boxType = typeof(PseudoBox<>).MakeGenericType(type); + + // Process all members + foreach (var m in ri.Members) + { + // Ignore write only properties + var pi = m.Member as PropertyInfo; + var fi = m.Member as FieldInfo; + if (pi != null && pi.GetSetMethod(true) == null) + { + continue; + } + + // Create a dynamic method that can do the work + var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true); + var il = method.GetILGenerator(); + + // Load the target + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, boxType); + il.Emit(OpCodes.Ldflda, boxType.GetField("value")); + + // Get the value + GenerateGetJsonValue(m, il); + + // Assign it + if (pi != null) + il.Emit(OpCodes.Call, pi.GetSetMethod(true)); + if (fi != null) + il.Emit(OpCodes.Stfld, fi); + + // Done + il.Emit(OpCodes.Ret); + + // Store in the map of setters + setters.Add(m.JsonKey, (Action)method.CreateDelegate(typeof(Action))); + } + + // Create helpers to invoke the interfaces (this is painful but avoids having to really box + // the value in order to call the interface). + Action invokeLoading = MakeInterfaceCall(type, typeof(IJsonLoading)); + Action invokeLoaded = MakeInterfaceCall(type, typeof(IJsonLoaded)); + Func invokeField = MakeLoadFieldCall(type); + + // Create the parser + Func parser = (reader, Type) => + { + // Create pseudobox (ie: new PseudoBox) + var box = DecoratingActivator.CreateInstance(boxType); + + // Call IJsonLoading + if (invokeLoading != null) + invokeLoading(box, reader); + + // Read the dictionary + reader.ParseDictionary(key => + { + // Call IJsonLoadField + if (invokeField != null && invokeField(box, reader, key)) + return; + + // Get a setter and invoke it if found + Action setter; + if (setters.TryGetValue(key, out setter)) + { + setter(reader, box); + } + }); + + // IJsonLoaded + if (invokeLoaded != null) + invokeLoaded(box, reader); + + // Return the value + return ((IPseudoBox)box).GetValue(); + }; + + // Done + return parser; + } + } + + // Helper to make the call to a PsuedoBox value's IJsonLoading or IJsonLoaded + static Action MakeInterfaceCall(Type type, Type tItf) + { + // Interface supported? + if (!tItf.IsAssignableFrom(type)) + return null; + + // Resolve the box type + var boxType = typeof(PseudoBox<>).MakeGenericType(type); + + // Create method + var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, null, new Type[] { typeof(object), typeof(IJsonReader) }, true); + var il = method.GetILGenerator(); + + // Call interface method + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, boxType); + il.Emit(OpCodes.Ldflda, boxType.GetField("value")); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]); + il.Emit(OpCodes.Ret); + + // Done + return (Action)method.CreateDelegate(typeof(Action)); + } + + // Similar to above but for IJsonLoadField + static Func MakeLoadFieldCall(Type type) + { + // Interface supported? + var tItf = typeof(IJsonLoadField); + if (!tItf.IsAssignableFrom(type)) + return null; + + // Resolve the box type + var boxType = typeof(PseudoBox<>).MakeGenericType(type); + + // Create method + var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, typeof(bool), new Type[] { typeof(object), typeof(IJsonReader), typeof(string) }, true); + var il = method.GetILGenerator(); + + // Call interface method + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, boxType); + il.Emit(OpCodes.Ldflda, boxType.GetField("value")); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]); + il.Emit(OpCodes.Ret); + + // Done + return (Func)method.CreateDelegate(typeof(Func)); + } + + // Create an "into parser" that can parse from IJsonReader into a reference type (ie: a class) + public static Action MakeIntoParser(Type type) + { + System.Diagnostics.Debug.Assert(!type.IsValueType); + + // Get the reflection info for this type + var ri = ReflectionInfo.GetReflectionInfo(type); + if (ri == null) + return null; + + // We'll create setters for each property/field + var setters = new Dictionary>(); + + // Process all members + foreach (var m in ri.Members) + { + // Ignore write only properties + var pi = m.Member as PropertyInfo; + var fi = m.Member as FieldInfo; + if (pi != null && pi.GetSetMethod(true) == null) + { + continue; + } + + // Ignore read only properties that has KeepInstance attribute + if (pi != null && pi.GetGetMethod(true) == null && m.KeepInstance) + { + continue; + } + + // Create a dynamic method that can do the work + var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true); + var il = method.GetILGenerator(); + + // Load the target + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); + + // Try to keep existing instance? + if (m.KeepInstance) + { + // Get existing existing instance + il.Emit(OpCodes.Dup); + if (pi != null) + il.Emit(OpCodes.Callvirt, pi.GetGetMethod(true)); + else + il.Emit(OpCodes.Ldfld, fi); + + var existingInstance = il.DeclareLocal(m.MemberType); + var lblExistingInstanceNull = il.DefineLabel(); + + // Keep a copy of the existing instance in a locale + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc, existingInstance); + + // Compare to null + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Ceq); + il.Emit(OpCodes.Brtrue_S, lblExistingInstanceNull); + + il.Emit(OpCodes.Ldarg_0); // reader + il.Emit(OpCodes.Ldloc, existingInstance); // into + il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("ParseInto", new Type[] { typeof(Object) })); + + il.Emit(OpCodes.Pop); // Clean up target left on stack (1) + il.Emit(OpCodes.Ret); + + il.MarkLabel(lblExistingInstanceNull); + } + + // Get the value from IJsonReader + GenerateGetJsonValue(m, il); + + // Assign it + if (pi != null) + il.Emit(OpCodes.Callvirt, pi.GetSetMethod(true)); + if (fi != null) + il.Emit(OpCodes.Stfld, fi); + + // Done + il.Emit(OpCodes.Ret); + + // Store the handler in map + setters.Add(m.JsonKey, (Action)method.CreateDelegate(typeof(Action))); + } + + + // Now create the parseInto delegate + Action parseInto = (reader, obj) => + { + // Call IJsonLoading + var loading = obj as IJsonLoading; + if (loading != null) + loading.OnJsonLoading(reader); + + // Cache IJsonLoadField + var lf = obj as IJsonLoadField; + + // Read dictionary keys + reader.ParseDictionary(key => + { + // Call IJsonLoadField + if (lf != null && lf.OnJsonField(reader, key)) + return; + + // Call setters + Action setter; + if (setters.TryGetValue(key, out setter)) + { + setter(reader, obj); + } + }); + + // Call IJsonLoaded + var loaded = obj as IJsonLoaded; + if (loaded != null) + loaded.OnJsonLoaded(reader); + }; + + // Since we've created the ParseInto handler, we might as well register + // as a Parse handler too. + RegisterIntoParser(type, parseInto); + + // Done + return parseInto; + } + + // Registers a ParseInto handler as Parse handler that instantiates the object + // and then parses into it. + static void RegisterIntoParser(Type type, Action parseInto) + { + // Check type has a parameterless constructor + var con = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); + if (con == null) + return; + + // Create a dynamic method that can do the work + var method = new DynamicMethod("dynamic_factory", typeof(object), new Type[] { typeof(IJsonReader), typeof(Action) }, true); + var il = method.GetILGenerator(); + + // Create the new object + var locObj = il.DeclareLocal(typeof(object)); + il.Emit(OpCodes.Newobj, con); + + il.Emit(OpCodes.Dup); // For return value + + il.Emit(OpCodes.Stloc, locObj); + + il.Emit(OpCodes.Ldarg_1); // parseinto delegate + il.Emit(OpCodes.Ldarg_0); // IJsonReader + il.Emit(OpCodes.Ldloc, locObj); // new object instance + il.Emit(OpCodes.Callvirt, typeof(Action).GetMethod("Invoke")); + il.Emit(OpCodes.Ret); + + var factory = (Func, object>)method.CreateDelegate(typeof(Func, object>)); + + Json.RegisterParser(type, (reader, type2) => + { + return factory(reader, parseInto); + }); + } + + // Generate the MSIL to retrieve a value for a particular field or property from a IJsonReader + private static void GenerateGetJsonValue(JsonMemberInfo m, ILGenerator il) + { + Action generateCallToHelper = helperName => + { + // Call the helper + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, typeof(Emit).GetMethod(helperName, new Type[] { typeof(IJsonReader) })); + + // Move to next token + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { })); + }; + + Type[] numericTypes = new Type[] { + typeof(int), typeof(uint), typeof(long), typeof(ulong), + typeof(short), typeof(ushort), typeof(decimal), + typeof(byte), typeof(sbyte), + typeof(double), typeof(float) + }; + + if (m.MemberType == typeof(string)) + { + generateCallToHelper("GetLiteralString"); + } + + else if (m.MemberType == typeof(bool)) + { + generateCallToHelper("GetLiteralBool"); + } + + else if (m.MemberType == typeof(char)) + { + generateCallToHelper("GetLiteralChar"); + } + + else if (numericTypes.Contains(m.MemberType)) + { + // Get raw number string + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Call, typeof(Emit).GetMethod("GetLiteralNumber", new Type[] { typeof(IJsonReader) })); + + // Convert to a string + il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod()); + il.Emit(OpCodes.Call, m.MemberType.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) })); + + // + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { })); + } + + else + { + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldtoken, m.MemberType); + il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) })); + il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("Parse", new Type[] { typeof(Type) })); + il.Emit(m.MemberType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, m.MemberType); + } + } + + // Helper to fetch a literal bool from an IJsonReader + [Obfuscation(Exclude = true)] + public static bool GetLiteralBool(IJsonReader r) + { + switch (r.GetLiteralKind()) + { + case LiteralKind.True: + return true; + + case LiteralKind.False: + return false; + + default: + throw new InvalidDataException("expected a boolean value"); + } + } + + // Helper to fetch a literal character from an IJsonReader + [Obfuscation(Exclude = true)] + public static char GetLiteralChar(IJsonReader r) + { + if (r.GetLiteralKind() != LiteralKind.String) + throw new InvalidDataException("expected a single character string literal"); + var str = r.GetLiteralString(); + if (str == null || str.Length != 1) + throw new InvalidDataException("expected a single character string literal"); + + return str[0]; + } + + // Helper to fetch a literal string from an IJsonReader + [Obfuscation(Exclude = true)] + public static string GetLiteralString(IJsonReader r) + { + switch (r.GetLiteralKind()) + { + case LiteralKind.Null: return null; + case LiteralKind.String: return r.GetLiteralString(); + } + throw new InvalidDataException("expected a string literal"); + } + + // Helper to fetch a literal number from an IJsonReader (returns the raw string) + [Obfuscation(Exclude = true)] + public static string GetLiteralNumber(IJsonReader r) + { + switch (r.GetLiteralKind()) + { + case LiteralKind.SignedInteger: + case LiteralKind.UnsignedInteger: + case LiteralKind.FloatingPoint: + return r.GetLiteralString(); + } + throw new InvalidDataException("expected a numeric literal"); + } + } +#endif + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/RevokeGlobalCardRequest.cs b/SDK/Source/Virgil.SDK.Shared/Common/PetaJsonSerializer.cs similarity index 58% rename from SDK/Source/Virgil.SDK.Shared/Client/RevokeGlobalCardRequest.cs rename to SDK/Source/Virgil.SDK.Shared/Common/PetaJsonSerializer.cs index 734b038e..b1d91d51 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/RevokeGlobalCardRequest.cs +++ b/SDK/Source/Virgil.SDK.Shared/Common/PetaJsonSerializer.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,31 +34,44 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Common { - /// - /// Represents an information about revoking card request. - /// - public class RevokeGlobalCardRequest : SignableRequest + using System; + using PetaJson; + using System.Text; + + public class PetaJsonSerializer : IJsonSerializer { - /// - /// Initializes a new instance of the class. - /// - /// The stringified request. - public RevokeGlobalCardRequest(string stringifiedRequest) : base(stringifiedRequest) + public PetaJsonSerializer() + { + Json.RegisterFormatter(this.DateTimeFormatter); + Json.RegisterParser(this.DateTimeParser); + } + + public string Serialize(object model) + { + return Json.Format(model); + } + + public TModel Deserialize(string json) { + return Json.Parse(json); + } + + private DateTime DateTimeParser(object o) + { + var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + + // Add the timestamp (number of seconds since the Epoch) to be converted + var unixTimeStamp = Int64.Parse(o.ToString()); + return dateTime.AddSeconds(unixTimeStamp); } - /// - /// Initializes a new instance of the class. - /// - /// The card ID to be revoked. - /// The revocation reason. - /// The validation token. - public RevokeGlobalCardRequest(string cardId, RevocationReason reason, string validationToken) - : base(new RevokeCardSnapshotModel { CardId = cardId, Reason = reason }) + private void DateTimeFormatter(IJsonWriter jsonWriter, DateTime dateTime) { - this.validationToken = validationToken; + var timeSpan = dateTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + var unixTimestamp = (Int64)timeSpan.TotalSeconds; + jsonWriter.WriteValue(unixTimestamp); } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Common/RawSignedModelUtils.cs b/SDK/Source/Virgil.SDK.Shared/Common/RawSignedModelUtils.cs new file mode 100644 index 00000000..3de457ab --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/RawSignedModelUtils.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Virgil.CryptoAPI; +using Virgil.SDK.Web; + +namespace Virgil.SDK.Common +{ + public class RawSignedModelUtils + { + const string CardVersion = "5.0"; + + /// + /// Loads from the specified . + /// + /// an instance of . + /// an instance of to get + /// from. + /// Loaded instance of . + public static RawSignedModel Parse(ICardCrypto cardCrypto, Card card) + { + ValidateParams(cardCrypto, card); + var rawSignedModel = Generate( + cardCrypto, + new CardParams() + { + Identity = card.Identity, + PreviousCardId = card.PreviousCardId, + PublicKey = card.PublicKey + }, + card.CreatedAt); + rawSignedModel.Signatures = new List(); + + foreach (var signature in card.Signatures) + { + rawSignedModel.Signatures.Add( + new RawSignature() + { + Signature = signature.Signature, + Signer = signature.Signer, + Snapshot = signature.Snapshot + } + ); + } + return rawSignedModel; + } + + private static void ValidateParams(ICardCrypto cardCrypto, Card rawSignedModel) + { + if (rawSignedModel == null) + { + throw new ArgumentNullException(nameof(rawSignedModel)); + } + + if (cardCrypto == null) + { + throw new ArgumentNullException(nameof(cardCrypto)); + } + } + + + internal static RawSignedModel Generate( + ICardCrypto cardCrypto, + CardParams @params, + DateTime createdAt) + { + ValidateGenerateParams(cardCrypto, @params); + + var details = new RawCardContent + { + Identity = @params.Identity, + PublicKey = cardCrypto.ExportPublicKey(@params.PublicKey), + Version = CardVersion, + CreatedAt = createdAt, + PreviousCardId = @params.PreviousCardId + }; + + return new RawSignedModel() + { + ContentSnapshot = SnapshotUtils.TakeSnapshot(details) + }; + } + + + private static void ValidateGenerateParams(ICardCrypto cardCrypto, CardParams @params) + { + if (cardCrypto == null) + { + throw new ArgumentNullException(nameof(cardCrypto)); + } + + if (@params == null) + { + throw new ArgumentNullException(nameof(@params)); + } + + if (@params.Identity == null) + { + throw new ArgumentException($"{nameof(@params.Identity)} property is mandatory"); + } + if (@params.PublicKey == null) + { + throw new ArgumentException($"{nameof(@params.PublicKey)} property is mandatory"); + } + + } + + /// + /// Imports RawSignedModel from BASE64 string. + /// + /// The exported as BASE64 string. + /// The instance of class. + /// + public static RawSignedModel GenerateFromString(string str) + { + if (str == null) + { + throw new ArgumentNullException(nameof(str)); + + } + var strBytes = Bytes.FromString(str, StringEncoding.BASE64); + var requestJson = Bytes.ToString(strBytes); + return GenerateFromJson(requestJson); + } + + /// + /// Imports RawSignedModel from specified json. + /// + /// The exported as json. + /// The instance of class. + /// + public static RawSignedModel GenerateFromJson(string json) + { + if (json == null) + { + throw new ArgumentNullException(nameof(json)); + + } + RawSignedModel rawSignedModel; + try + { + rawSignedModel = Configuration.Serializer.Deserialize(json); + } + catch (Exception) + { + throw new ArgumentException($"{nameof(json)} wrong format."); + } + return rawSignedModel; + } + + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Common/SnapshotUtils.cs b/SDK/Source/Virgil.SDK.Shared/Common/SnapshotUtils.cs new file mode 100644 index 00000000..e7fb6b88 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Common/SnapshotUtils.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Virgil.SDK; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Common +{ + public class SnapshotUtils + { + /// + /// Get snapshot of specified object. + /// + /// the object to get snapshot from. + /// snapshot data. + public static byte[] TakeSnapshot(object info) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + var snapshotModelJson = Configuration.Serializer.Serialize(info); + var takenSnapshot = Bytes.FromString(snapshotModelJson); + + return takenSnapshot; + } + + /// + /// Gets object by its snapshot. + /// + /// the type of object that we expect to receive. + /// the snapshot to get the object from. + /// object + public static TSnaphotModel ParseSnapshot(byte[] snapshot) + { + if (snapshot == null) + { + throw new ArgumentNullException(nameof(snapshot)); + } + var snapshotModelJson = Bytes.ToString(snapshot); + var snapshotModel = Configuration.Serializer.Deserialize(snapshotModelJson); + + return snapshotModel; + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/StringEncoding.cs b/SDK/Source/Virgil.SDK.Shared/Common/StringEncoding.cs similarity index 90% rename from SDK/Source/Virgil.SDK.Shared/StringEncoding.cs rename to SDK/Source/Virgil.SDK.Shared/Common/StringEncoding.cs index a102d33e..eede73f8 100644 --- a/SDK/Source/Virgil.SDK.Shared/StringEncoding.cs +++ b/SDK/Source/Virgil.SDK.Shared/Common/StringEncoding.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,12 +34,12 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK +namespace Virgil.SDK.Common { public enum StringEncoding { - Base64, - Hex, - Utf8 + BASE64, + HEX, + UTF8 } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Configuration.cs b/SDK/Source/Virgil.SDK.Shared/Configuration.cs new file mode 100644 index 00000000..e615b198 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Configuration.cs @@ -0,0 +1,59 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.SDK +{ + using System; + using Virgil.SDK.Common; + + public class Configuration + { + private static volatile IJsonSerializer serializer; + public static IJsonSerializer Serializer + { + get => serializer ?? (serializer = new PetaJsonSerializer()); + set + { + if (serializer == null) + { + throw new InvalidOperationException(); + } + + serializer = value; + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Cryptography/KeyPairType.cs b/SDK/Source/Virgil.SDK.Shared/Cryptography/KeyPairType.cs deleted file mode 100644 index 0c9ac578..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Cryptography/KeyPairType.cs +++ /dev/null @@ -1,57 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Cryptography -{ - public enum KeyPairType - { - Default, - RSA_2048, - RSA_3072, - RSA_4096, - RSA_8192, - EC_SECP256R1, - EC_SECP384R1, - EC_SECP521R1, - EC_BP256R1, - EC_BP384R1, - EC_BP512R1, - EC_SECP256K1, - EC_CURVE25519, - FAST_EC_X25519, - FAST_EC_ED25519 - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Cryptography/PublicKey.cs b/SDK/Source/Virgil.SDK.Shared/Cryptography/PublicKey.cs deleted file mode 100644 index 4cc88b8e..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Cryptography/PublicKey.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Cryptography -{ - /// - /// The object represents an opaque reference to keying material - /// that is managed by the agent. - /// - internal class PublicKey : IPublicKey - { - /// - /// Gets or sets the receiver identifier. - /// - internal byte[] ReceiverId { get; set; } - - /// - /// Gets the public key. - /// - internal byte[] Value { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCrypto.cs b/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCrypto.cs deleted file mode 100644 index e9f3b5e0..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCrypto.cs +++ /dev/null @@ -1,722 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Cryptography -{ - using System; - using System.IO; - using System.Text; - using System.Linq; - using Virgil.Crypto; - using Virgil.Crypto.Foundation; - - using Virgil.SDK.Exceptions; - - /// - /// The class provides a cryptographic operations in applications, such as hashing, - /// signature generation and verification, and encryption and decryption. - /// - public sealed class VirgilCrypto : Crypto - { - private readonly KeyPairType defaultKeyPairType; - private readonly byte[] CustomParamKeySignature = Encoding.UTF8.GetBytes("VIRGIL-DATA-SIGNATURE"); - private readonly byte[] CustomParamKeySignerId = Encoding.UTF8.GetBytes("VIRGIL-DATA-SIGNER-ID"); - - /// - /// Initializes a new instance of the class. - /// - /// Default type of the key pair. - public VirgilCrypto(KeyPairType defaultKeyPairType) - { - this.defaultKeyPairType = defaultKeyPairType; - } - - /// - /// Initializes a new instance of the class. - /// - public VirgilCrypto() - { - this.defaultKeyPairType = KeyPairType.Default; - } - - /// - /// Generates asymmetric key pair that is comprised of both public and private keys by specified type. - /// - /// type of the generated keys. - /// The possible values can be found in . - /// Generated key pair with type EC_SECP256R1. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(KeyPairType.EC_SECP256R1); - /// - /// - public KeyPair GenerateKeys(KeyPairType keyPairType) - { - try - { - using (var keyPair = VirgilKeyPair.Generate(keyPairType.ToVirgilKeyPairType())) - { - var keyPairId = this.ComputePublicKeyHash(keyPair.PublicKey()); - var privateKey = new PrivateKey - { - ReceiverId = keyPairId, - Value = VirgilKeyPair.PrivateKeyToDER(keyPair.PrivateKey()), - }; - - var publicKey = new PublicKey - { - ReceiverId = keyPairId, - Value = VirgilKeyPair.PublicKeyToDER(keyPair.PublicKey()) - }; - - return new KeyPair(publicKey, privateKey); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Generates recommended asymmetric key pair that is comprised of both Public and Private keys. - /// - /// Generated key pair. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// - /// - public override KeyPair GenerateKeys() - { - return this.GenerateKeys(this.defaultKeyPairType); - } - - /// - /// Imports the Private key from material representation. - /// - /// - /// - /// var crypto = new VirgilCrypto(); - /// var publicKey = crypto.ImportPrivateKey(exportedPrivateKey); - /// - /// - /// How to get exportedPrivateKey - public override IPrivateKey ImportPrivateKey(byte[] keyData, string password = null) - { - if (keyData == null) - throw new ArgumentNullException(nameof(keyData)); - - try - { - var privateKeyBytes = string.IsNullOrEmpty(password) - ? keyData - : VirgilKeyPair.DecryptPrivateKey(keyData, Encoding.UTF8.GetBytes(password)); - - var publicKey = VirgilKeyPair.ExtractPublicKey(privateKeyBytes, new byte[] { }); - var privateKey = new PrivateKey - { - ReceiverId = this.ComputePublicKeyHash(publicKey), - Value = VirgilKeyPair.PrivateKeyToDER(privateKeyBytes) - }; - - return privateKey; - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Imports the Public key from material representation. - /// - /// public key material representation bytes. - /// Imported public key. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var publicKey = crypto.ImportPublicKey(exportedPublicKey); - /// - /// - /// How to get exportedPublicKey - public override IPublicKey ImportPublicKey(byte[] keyData) - { - try - { - var publicKey = new PublicKey - { - ReceiverId = this.ComputePublicKeyHash(keyData), - Value = VirgilKeyPair.PublicKeyToDER(keyData) - }; - - return publicKey; - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Exports the Private key into material representation. - /// - public override byte[] ExportPrivateKey(IPrivateKey privateKey, string password = null) - { - try - { - if (string.IsNullOrEmpty(password)) - { - return VirgilKeyPair.PrivateKeyToDER(privateKey.Get().Value); - } - - var passwordBytes = Encoding.UTF8.GetBytes(password); - var encryptedKey = VirgilKeyPair.EncryptPrivateKey(privateKey.Get().Value, passwordBytes); - - return VirgilKeyPair.PrivateKeyToDER(encryptedKey, passwordBytes); - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - - /// - /// Exports the Public key into material representation. - /// - /// public key for export. - /// Key material representation bytes. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// var exportedPublicKey = crypto.ExportPublicKey(keyPair.PublicKey); - /// - /// - public override byte[] ExportPublicKey(IPublicKey publicKey) - { - try - { - return VirgilKeyPair.PublicKeyToDER(publicKey.Get().Value); - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Extracts the Public key from Private key. - /// - public override IPublicKey ExtractPublicKey(IPrivateKey privateKey) - { - try - { - var publicKeyData = VirgilKeyPair.ExtractPublicKey(privateKey.Get().Value, new byte[] { }); - - var publicKey = new PublicKey - { - ReceiverId = privateKey.Get().ReceiverId, - Value = VirgilKeyPair.PublicKeyToDER(publicKeyData) - }; - - return publicKey; - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - - /// - /// Encrypts the specified data using recipients Public keys. - /// - /// raw data bytes for encryption. - /// list of recipients' public keys. - /// Encrypted bytes. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// var data = Encoding.UTF8.GetBytes("Encrypt me!"); - /// var encryptedData = crypto.Encrypt(data, keyPair.PublicKey); - /// - /// - public override byte[] Encrypt(byte[] data, params IPublicKey[] recipients) - { - try - { - using (var cipher = new VirgilCipher()) - { - foreach (var publicKey in recipients) - { - cipher.AddKeyRecipient(publicKey.Get().ReceiverId, publicKey.Get().Value); - } - - var encryptedData = cipher.Encrypt(data, true); - return encryptedData; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - /// - /// Decrypts the specified data using Private key. - /// - /// encrypted data bytes for decryption. - /// private key for decryption. - /// Decrypted data bytes. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// var plainData = crypto.Decrypt(encryptedData, keyPair.PrivateKey); - /// - /// - /// How to get encryptedData - public override byte[] Decrypt(byte[] cipherData, IPrivateKey privateKey) - { - try - { - using (var cipher = new VirgilCipher()) - { - var data = cipher.DecryptWithKey(cipherData, privateKey.Get().ReceiverId, privateKey.Get().Value); - return data; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - /// - /// Signs the specified data using Private key. - /// - /// raw data bytes for signing. - /// private key for signing. - /// Signature data. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// var data = Encoding.UTF8.GetBytes("Hello Bob!"); - /// var sugnature = crypto.Sign(data, keyPair.PrivateKey); - /// - /// - public override byte[] Sign(byte[] data, IPrivateKey privateKey) - { - if (data == null) - throw new ArgumentNullException(nameof(data)); - - if (privateKey == null) - throw new ArgumentNullException(nameof(privateKey)); - - try - { - using (var signer = new VirgilSigner()) - { - var signature = signer.Sign(data, privateKey.Get().Value); - return signature; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - /// - /// Verifies the specified signature using original data and signer's Public key. - /// - /// original data bytes for verification. - /// signature bytes for verification. - /// signer public key for verification. - /// True if signature is valid, False otherwise. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var publicKey = crypto.ImportPublicKey(exportedPublicKey); - /// var data = Encoding.UTF8.GetBytes("Hello Bob!"); - /// crypto.Verify(data, signature, publicKey) - /// - /// - /// How to get signature - /// How to get exportedPublicKey - public override bool Verify(byte[] data, byte[] signature, IPublicKey signerKey) - { - if (data == null) - throw new ArgumentNullException(nameof(data)); - - if (signature == null) - throw new ArgumentNullException(nameof(signature)); - - try - { - using (var virgilSigner = new VirgilSigner()) - { - var isValid = virgilSigner.Verify(data, signature, signerKey.Get().Value); - return isValid; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Encrypts the specified stream using recipients Public keys. - /// - /// readable stream containing input bytes. - /// writable stream for output. - /// list of recipients' public keys. - /// Encrypted bytes. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var aliceKeyPair = crypto.GenerateKeys(); - /// var bobKeyPair = crypto.GenerateKeys(); - /// using (var inputStream = new FileStream("[YOUR_FILE_PATH_HERE]", - /// FileMode.Open, FileAccess.Read)) - /// { - /// using (var cipherStream = new FileStream("[YOUR_CIPHER_FILE_PATH_HERE]", - /// FileMode.Create, FileAccess.Write)) - /// { - /// crypto.Encrypt(inputStream, cipherStream, aliceKeyPair.PublicKey, bobKeyPair.PublicKey); - /// } - /// } - /// - /// - public override void Encrypt(Stream inputStream, Stream cipherStream, params IPublicKey[] recipients) - { - try - { - using (var cipher = new VirgilChunkCipher()) - using (var source = new VirgilStreamDataSource(inputStream)) - using (var sink = new VirgilStreamDataSink(cipherStream)) - { - foreach (var publicKey in recipients) - { - cipher.AddKeyRecipient(publicKey.Get().ReceiverId, publicKey.Get().Value); - } - - cipher.Encrypt(source, sink); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - /// - /// Decrypts the specified stream using Private key. - /// readable stream containing encrypted data. - /// writable stream for output. - /// private key for decryption. - /// - /// - /// - /// var crypto = new VirgilCrypto(); - /// var alicePrivateKey = crypto.ImportPrivateKey(exportedPrivateKey); - /// using (var encryptedStream = new FileStream("[YOUR_CIPHER_FILE_PATH_HERE]", - /// FileMode.Open, FileAccess.Read)) - /// { - /// using (var decryptedStream = new FileStream("[YOUR_DECRYPTED_FILE_PATH_HERE]", - /// FileMode.Create, FileAccess.Write)) - /// { - /// crypto.Decrypt(encryptedStream, decryptedStream, alicePrivateKey); - /// } - /// } - /// - /// - /// How to get encryptedStream - /// How to get exportedPrivateKey - public override void Decrypt(Stream cipherStream, Stream outputStream, IPrivateKey privateKey) - { - try - { - using (var cipher = new VirgilChunkCipher()) - using (var source = new VirgilStreamDataSource(cipherStream)) - using (var sink = new VirgilStreamDataSink(outputStream)) - { - cipher.DecryptWithKey(source, sink, privateKey.Get().ReceiverId, privateKey.Get().Value); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - /// - /// Signs and encrypts the data. - /// - /// The data to encrypt. - /// The Private key to sign the data. - /// The list of Public key recipients to encrypt the data. - /// Signed and encrypted data bytes. - /// - /// - /// - /// var crypto = new VirgilCrypto(); - /// - /// var alice = crypto.GenerateKeys(); - /// var bob = crypto.GenerateKeys(); - /// var originalData = Encoding.UTF8.GetBytes("Hello Bob, How are you?"); - /// // The data to be signed with Alice's Private key and then encrypted for Bob. - /// var cipherData = crypto.SignThenEncrypt(originalData, alice.PrivateKey, bob.PublicKey); - /// - /// - public override byte[] SignThenEncrypt(byte[] data, IPrivateKey privateKey, params IPublicKey[] recipients) - { - try - { - using (var signer = new VirgilSigner()) - using (var cipher = new VirgilCipher()) - { - var signature = signer.Sign(data, privateKey.Get().Value); - - var customData = cipher.CustomParams(); - customData.SetData(this.CustomParamKeySignature, signature); - - var publicKey = this.ExtractPublicKey(privateKey); - - customData.SetData(this.CustomParamKeySignerId, publicKey.Get().ReceiverId); - - foreach (var recipientPublicKey in recipients) - { - cipher.AddKeyRecipient(recipientPublicKey.Get().ReceiverId, recipientPublicKey.Get().Value); - } - - return cipher.Encrypt(data, true); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Decrypts and verifies the data. - /// - /// The cipher data. - /// The Private key to decrypt. - /// The list of trusted public keys for verification, - /// which can contain signer's public key. - /// The decrypted data - /// - /// - /// - /// - /// var crypto = new VirgilCrypto(); - /// var decryptedData = crypto.DecryptThenVerify(cipherData, bob.PrivateKey, alice.PublicKey); - /// - /// - /// How to get cipherData as well as Alice's and Bob's key pairs. - /// - public override byte[] DecryptThenVerify(byte[] cipherData, IPrivateKey privateKey, params IPublicKey[] publicKeys) - { - try - { - using (var signer = new VirgilSigner()) - using (var cipher = new VirgilCipher()) - { - var decryptedData = cipher.DecryptWithKey(cipherData, privateKey.Get().ReceiverId, privateKey.Get().Value); - var signature = cipher.CustomParams().GetData(this.CustomParamKeySignature); - - var signerPublicKey = publicKeys.FirstOrDefault(); - if (publicKeys.Length > 1) - { - var signerId = cipher.CustomParams().GetData(this.CustomParamKeySignerId); - signerPublicKey = publicKeys.Single(publicKey => publicKey.Get().ReceiverId.SequenceEqual(signerId)); - } - - var isValid = signer.Verify(decryptedData, signature, signerPublicKey.Get().Value); - if (!isValid) - throw new SignatureIsNotValidException(); - - return decryptedData; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - - - - /// - /// Signs the specified stream using Private key. - /// - /// readable stream containing input data. - /// private key for signing. - /// Signature data. - /// - /// - /// var crypto = new VirgilCrypto(); - /// var keyPair = crypto.GenerateKeys(); - /// using (var inputStream = new FileStream("[YOUR_FILE_PATH_HERE]", FileMode.Open, FileAccess.Read)) - /// { - /// signature = crypto.Sign(inputStream, keyPair.PrivateKey); - /// } - /// - /// - public override byte[] Sign(Stream inputStream, IPrivateKey privateKey) - { - try - { - using (var signer = new VirgilStreamSigner()) - using (var source = new VirgilStreamDataSource(inputStream)) - { - var signature = signer.Sign(source, privateKey.Get().Value); - return signature; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Calculates the fingerprint. - /// - public override Fingerprint CalculateFingerprint(byte[] content) - { - if (content == null) - throw new ArgumentNullException(nameof(content)); - - try - { - using (var sha256 = new VirgilHash(VirgilHash.Algorithm.SHA256)) - { - var hash = sha256.Hash(content); - return new Fingerprint(hash); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Computes the hash of specified data. - /// - public override byte[] ComputeHash(byte[] data, HashAlgorithm algorithm) - { - if (data == null) - throw new ArgumentNullException(nameof(data)); - - var virgilHashAlg = (VirgilHash.Algorithm)algorithm; - var hasher = new VirgilHash(virgilHashAlg); - - try - { - using (hasher) - { - return hasher.Hash(data); - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - /// - /// Verifies the specified signature using original stream and signer's Public key. - /// - /// readable stream containing input data. - /// signer public key for verification. - /// signature bytes for verification. - /// True if signature is valid, False otherwise. - /// - /// - /// var publicKey = crypto.ImportPublicKey(exportedPublicKey); - /// using (var inputStream = new FileStream("[YOUR_FILE_PATH_HERE]", FileMode.Open, FileAccess.Read)) - /// { - /// crypto.Verify(inputStream, signature, publicKey); - /// } - /// - /// - /// How to get exportedPublicKey - public override bool Verify(Stream inputStream, byte[] signature, IPublicKey publicKey) - { - if (signature == null) - throw new ArgumentNullException(nameof(signature)); - - try - { - using (var streamSigner = new VirgilStreamSigner()) - { - var source = new VirgilStreamDataSource(inputStream); - var isValid = streamSigner.Verify(source, signature, publicKey.Get().Value); - return isValid; - } - } - catch (Exception ex) - { - throw new CryptoException(ex.Message); - } - } - - private byte[] ComputePublicKeyHash(byte[] publicKey) - { - var publicKeyDER = VirgilKeyPair.PublicKeyToDER(publicKey); - return this.ComputeHash(publicKeyDER, HashAlgorithm.SHA256); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCryptoExtentions.cs b/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCryptoExtentions.cs deleted file mode 100644 index cdd6e79e..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Cryptography/VirgilCryptoExtentions.cs +++ /dev/null @@ -1,96 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Cryptography -{ - using System; - - using Virgil.Crypto; - - internal static class VirgilCryptoExtentions - { - public static VirgilKeyPair.Type ToVirgilKeyPairType(this KeyPairType keyPairType) - { - VirgilKeyPair.Type type; - - switch (keyPairType) - { - case KeyPairType.Default: type = VirgilKeyPair.Type.FAST_EC_ED25519; break; - case KeyPairType.RSA_2048: type = VirgilKeyPair.Type.RSA_2048; break; - case KeyPairType.RSA_3072: type = VirgilKeyPair.Type.RSA_3072; break; - case KeyPairType.RSA_4096: type = VirgilKeyPair.Type.RSA_4096; break; - case KeyPairType.RSA_8192: type = VirgilKeyPair.Type.RSA_8192; break; - case KeyPairType.EC_SECP256R1: type = VirgilKeyPair.Type.EC_SECP256R1; break; - case KeyPairType.EC_SECP384R1: type = VirgilKeyPair.Type.EC_SECP384R1; break; - case KeyPairType.EC_SECP521R1: type = VirgilKeyPair.Type.EC_SECP521R1; break; - case KeyPairType.EC_BP256R1: type = VirgilKeyPair.Type.EC_BP256R1; break; - case KeyPairType.EC_BP384R1: type = VirgilKeyPair.Type.EC_BP384R1; break; - case KeyPairType.EC_BP512R1: type = VirgilKeyPair.Type.EC_BP512R1; break; - case KeyPairType.EC_SECP256K1: type = VirgilKeyPair.Type.EC_SECP256K1; break; - case KeyPairType.EC_CURVE25519: type = VirgilKeyPair.Type.EC_CURVE25519; break; - case KeyPairType.FAST_EC_X25519: type = VirgilKeyPair.Type.FAST_EC_X25519; break; - case KeyPairType.FAST_EC_ED25519: type = VirgilKeyPair.Type.FAST_EC_ED25519; break; - - default: - throw new ArgumentOutOfRangeException(nameof(keyPairType), keyPairType, null); - } - - return type; - } - - internal static PublicKey Get(this IPublicKey publicKey) - { - var theKey = publicKey as PublicKey; - if (theKey != null) - { - return theKey; - } - - throw new NotSupportedException(); - } - - internal static PrivateKey Get(this IPrivateKey privateKey) - { - var theKey = privateKey as PrivateKey; - if (theKey != null) - { - return theKey; - } - - throw new NotSupportedException(); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/EmailConfirmation.cs b/SDK/Source/Virgil.SDK.Shared/EmailConfirmation.cs deleted file mode 100644 index 7e9caf3c..00000000 --- a/SDK/Source/Virgil.SDK.Shared/EmailConfirmation.cs +++ /dev/null @@ -1,66 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System.Threading.Tasks; - - using Virgil.SDK.Client; - - /// - /// The class provides a logic to confirm the email identity. - /// - public class EmailConfirmation : IdentityConfirmation - { - private readonly string confirmationCode; - - /// - /// Initializes a new instance of the class. - /// - public EmailConfirmation(string confirmationCode) - { - this.confirmationCode = confirmationCode; - } - - internal override async Task ConfirmAndGrabValidationTokenAsync(IdentityVerificationAttempt attempt, VirgilClient client) - { - var token = await client.ConfirmIdentityAsync(attempt.ActionId, this.confirmationCode, - (int)attempt.TimeToLive.TotalSeconds, attempt.CountToLive).ConfigureAwait(false); - - return token; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/AppCredentialsException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/AppCredentialsException.cs deleted file mode 100644 index 34a6b047..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/AppCredentialsException.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Represents errors occurred during application authentication. - /// - /// - public class AppCredentialsException : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - public AppCredentialsException() : - base("This action requires AppID and AppKey retrieved from development deshboard.") - { - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/CardValidationException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/CardValidationException.cs deleted file mode 100644 index 4cbd6aec..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/CardValidationException.cs +++ /dev/null @@ -1,54 +0,0 @@ -#region Copyright (C) 2016 Virgil Security Inc. -// Copyright (C) 2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Exceptions -{ - using System.Collections.Generic; - using Client; - - public class CardValidationException : VirgilException - { - /// - /// Gets the invalid cards. - /// - public IEnumerable InvalidCards { get; } - - internal CardValidationException(IEnumerable invalidCards) : base("One or more cards didn't pass the validation") - { - this.InvalidCards = invalidCards; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/IdentityServiceServiceException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/IdentityServiceServiceException.cs deleted file mode 100644 index 1ca67b81..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/IdentityServiceServiceException.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Base exception for all Identity Service exceptions - /// - /// - public class IdentityServiceServiceException : VirgilServiceException - { - /// - /// Initializes a new instance of the class. - /// - /// The error code. - /// The error message. - public IdentityServiceServiceException(int errorCode, string errorMessage) : base(errorCode, errorMessage) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/RelationException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/RelationException.cs deleted file mode 100644 index 76c9154e..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/RelationException.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Represents errors occurred during adding and removing relation. - /// - /// - public class RelationException : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - public RelationException() : - base("Request is not valid. Request must have snapshot and exactly 1 relation signature.") - { - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceIsAlreadyRegistered.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceIsAlreadyRegistered.cs deleted file mode 100644 index 9ccaa524..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceIsAlreadyRegistered.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class ServiceIsAlreadyRegistered : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - public ServiceIsAlreadyRegistered() : base("Type is already registered") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceNotRegisteredException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceNotRegisteredException.cs deleted file mode 100644 index 0bbb7335..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/ServiceNotRegisteredException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class ServiceNotRegisteredException : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - public ServiceNotRegisteredException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilCardIsNotFoundException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilCardIsNotFoundException.cs deleted file mode 100644 index 44396388..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilCardIsNotFoundException.cs +++ /dev/null @@ -1,51 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK.Exceptions -{ - /// - /// The exception that is thrown when an is not found. - /// - public class VirgilCardIsNotFoundException : VirgilApiException - { - /// - /// Initializes a new instance of the class. - /// - public VirgilCardIsNotFoundException() : base("The Virgil Card is not found") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilClientException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilClientException.cs deleted file mode 100644 index 530cf32e..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilClientException.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Public service exception - /// - /// - public class VirgilClientException : VirgilServiceException - { - /// - /// Initializes a new instance of the class. - /// - /// The error code. - /// The error message. - public VirgilClientException(int errorCode, string errorMessage) : base(errorCode, errorMessage) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilConfigIsNotInitializedException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilConfigIsNotInitializedException.cs deleted file mode 100644 index ab85d496..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilConfigIsNotInitializedException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class VirgilConfigIsNotInitializedException : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - public VirgilConfigIsNotInitializedException() : base(Localization.ExceptionVirgilConfigIsNotInitialized) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsAlreadyExistsException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsAlreadyExistsException.cs deleted file mode 100644 index 37ae1b06..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsAlreadyExistsException.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class VirgilKeyIsAlreadyExistsException : VirgilException - { - public VirgilKeyIsAlreadyExistsException() : base("Virgil Key is already exists.") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsNotFoundException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsNotFoundException.cs deleted file mode 100644 index f2abfead..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilKeyIsNotFoundException.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - public class VirgilKeyIsNotFoundException : VirgilException - { - public VirgilKeyIsNotFoundException() : base("Virgil Key is not found.") - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServiceException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServiceException.cs deleted file mode 100644 index ab9006d5..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServiceException.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Base exception class for all Virgil Services operations - /// - public class VirgilServiceException : VirgilException - { - /// - /// Initializes a new instance of the class. - /// - /// The error code. - /// The error message. - public VirgilServiceException(int errorCode, string errorMessage) : base(errorMessage) - { - this.ErrorCode = errorCode; - } - - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public VirgilServiceException(string message) : base(message) - { - } - - /// - /// Gets the error code. - /// - public int ErrorCode { get; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServicePrivateServicesException.cs b/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServicePrivateServicesException.cs deleted file mode 100644 index 32015646..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilServicePrivateServicesException.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Virgil.SDK.Exceptions -{ - /// - /// Private service exception - /// - /// - public class VirgilServicePrivateServicesException : VirgilServiceException - { - /// - /// Initializes a new instance of the class. - /// - /// The error code. - /// The error message. - public VirgilServicePrivateServicesException(int errorCode, string errorMessage) : base(errorCode, errorMessage) - { - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/ICardsManager.cs b/SDK/Source/Virgil.SDK.Shared/ICardsManager.cs deleted file mode 100644 index 2d7a580f..00000000 --- a/SDK/Source/Virgil.SDK.Shared/ICardsManager.cs +++ /dev/null @@ -1,286 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System.Collections.Generic; - using System.Threading.Tasks; - - /// - /// The interface defines a list of methods to manage the s. - /// - public interface ICardsManager - { - /// - /// Creates a new that is representing user's Public key and information - /// about identity. This card has to be published to the Virgil's services. - /// - /// The user's identity. - /// Type of the identity. - /// The owner's . - /// The custom fields (optional). - /// A new instance of class, that is representing user's Public key. - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// - /// // generate a new Virgil Key - /// var aliceKey = virgil.Keys.Generate() - /// - /// - /// // save the Virgil Key into the storage - /// aliceKey.Save("[KEY_NAME]", "[KEY_PASSWORD]"); - /// // create a Virgil Card - /// var aliceCard = virgil.Cards.Create("alice", aliceKey); - /// // DEVELOPERS HAVE TO TRANSMIT THE VIRGIL CARD TO THE APP'S - /// // SERVER SIDE WHERE IT WILL BE SIGNED, VALIDATED AND THEN PUBLISHED ON - /// // VIRGIL SERVICES (THIS IS NECESSARY FOR FURTHER OPERATIONS WITH THE VIRGIL CARD). - /// - /// - /// How to export the Virgil Card - VirgilCard Create(string identity, VirgilKey ownerKey, - string identityType = "unknown", - Dictionary customFields = null); - - - /// - /// Creates a new global that is representing user's - /// Public key and information about identity. - /// - /// The user's identity value. - /// Type of the identity. - /// The owner's . - /// The custom fields (optional). - /// A new instance of class, that is representing user's Public key. - /// - /// - /// var virgil = new VirgilApi(); - /// - /// // generate a new Virgil Key - /// var aliceKey = virgil.Keys.Generate() - /// - /// // save the Virgil Key into the storage - /// aliceKey.Save("[KEY_NAME]", "[KEY_PASSWORD]"); - /// - /// // create a Global Virgil Card - /// var aliceGlobalCard = virgil.Cards.CreateGlobal( - /// identity: "alice@virgilsecurity.com", - /// identityType: IdentityType.Email, - /// ownerKey: aliceKey); - /// - /// - VirgilCard CreateGlobal(string identity, IdentityType identityType, VirgilKey ownerKey, - Dictionary customFields = null); - - - /// - /// Finds a s by specified identities in application scope. - /// - /// The list of identities. - /// A list of found s. - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// // search for all User's Virgil Cards. - /// var aliceCards = await virgil.Cards.FindAsync("alice"); - /// - /// - Task> FindAsync(params string[] identities); - - - /// - /// Finds s by specified identities and type in application scope. - /// - /// Type of identity - /// The list of sought identities - /// A list of found s. - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// // search for all User's Virgil Cards with identity type 'member' - /// var bobCards = await virgil.Cards.FindAsync("member", new[] { "bob" }); - /// - /// - Task> FindAsync(string identityType, IEnumerable identities); - - - /// - /// Finds s by specified identities and type in global scope. - /// - /// The list of sought identities - /// A list of found s. - Task> FindGlobalAsync(params string[] identities); - - - /// - /// Finds s by specified identities and type in global scope. - /// - /// Type of identity - /// The list of sought identities - /// A list of found s. - Task> FindGlobalAsync(IdentityType identityType, params string[] identities); - - - /// - /// Imports a from specified buffer. - /// - /// The Card in string representation. - /// An instance of . - /// - /// - /// var virgil = new VirgilApi(new VirgilApiContext - /// { - /// AccessToken = "[YOUR_ACCESS_TOKEN_HERE]", - /// Credentials = new AppCredentials - /// { - /// AppId = "[YOUR_APP_ID_HERE]", - /// AppKey = VirgilBuffer.FromFile("[YOUR_APP_KEY_FILEPATH_HERE]"), - /// AppKeyPassword = "[YOUR_APP_KEY_PASSWORD_HERE]", - /// } - /// }); - /// - /// // import a Virgil Card from string - /// var aliceCard = virgil.Cards.Import(exportedAliceCard); - /// - /// How to get exportedAliceCard - /// - VirgilCard Import(string exportedCard); - - - /// - /// Publishes a into global Virgil Services scope. - /// - /// The Card to be published. - /// The identity validation token. - /// - /// - /// var virgil = new VirgilApi(); - /// - /// // initiate identity verification process - /// var attempt = await aliceGlobalCard.CheckIdentityAsync(); - /// - /// // confirm an identity and grab the validation token - /// var token = await attempt.ConfirmAsync(new EmailConfirmation("[CONFIRMATION_CODE]")); - /// - /// // publish the Virgil Card - /// await virgil.Cards.PublishGlobalAsync(aliceGlobalCard, token); - /// - /// - /// - /// How to get aliceGlobalCard - /// - /// - /// - /// Initiates an identity verification process for current Card identity type. - /// - /// - /// - /// Confirms an identity and generates a validation token that can - /// be used to perform operations like Publish and Revoke global Cards. - /// - /// - Task PublishGlobalAsync(VirgilCard card, IdentityValidationToken token); - - - /// - /// Publishes a into application Virgil Services scope. - /// - /// The Card to be published. - /// - /// - /// var virgil = new VirgilApi(new VirgilApiContext - /// { - /// AccessToken = "[YOUR_ACCESS_TOKEN_HERE]", - /// Credentials = new AppCredentials - /// { - /// AppId = "[YOUR_APP_ID_HERE]", - /// AppKey = VirgilBuffer.FromFile("[YOUR_APP_KEY_FILEPATH_HERE]"), - /// AppKeyPassword = "[YOUR_APP_KEY_PASSWORD_HERE]", - /// } - /// }); - /// - /// // publish a Virgil Card - /// await virgil.Cards.PublishAsync(aliceCard); - /// - /// How to get aliceCard - /// - Task PublishAsync(VirgilCard card); - - - /// - /// Revokes a from Virgil Services. - /// - /// The card to be revoked. - /// - /// - /// var virgil = new VirgilApi(new VirgilApiContext - /// { - /// AccessToken = "[YOUR_ACCESS_TOKEN_HERE]", - /// Credentials = new AppCredentials - /// { - /// AppId = "[YOUR_APP_ID_HERE]", - /// AppKey = VirgilBuffer.FromFile("[YOUR_APP_KEY_FILEPATH_HERE]"), - /// AppKeyPassword = "[YOUR_APP_KEY_PASSWORD_HERE]", - /// } - /// }); - /// - /// // get a Virgil Card by ID - /// var aliceCard = await virgil.Cards.GetAsync("[USER_CARD_ID_HERE]"); - /// - /// // revoke a Virgil Card - /// await virgil.Cards.RevokeAsync(aliceCard); - /// - /// Get card by Id - /// - Task RevokeAsync(VirgilCard card); - - - /// - /// Revokes a global from Virgil Security services. - /// - /// The Card to be revoked. - /// The Key associated with the revoking Card. - /// The identity token. - Task RevokeGlobalAsync(VirgilCard card, VirgilKey key, IdentityValidationToken identityToken); - - - /// - /// Gets the by specified ID. - /// - /// The Card identifier. - Task GetAsync(string cardId); - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IKeysManager.cs b/SDK/Source/Virgil.SDK.Shared/IKeysManager.cs deleted file mode 100644 index ad7c075b..00000000 --- a/SDK/Source/Virgil.SDK.Shared/IKeysManager.cs +++ /dev/null @@ -1,108 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - - using Virgil.SDK.Exceptions; - - /// - /// The interface defines a list of methods to generate the s - /// and further them storage in secure place. - /// - public interface IKeysManager - { - /// - /// Generates a new with default parameters. - /// - /// - /// - /// var virgil = new VirgilApi(); - /// // generate a new Virgil Key - /// var aliceKey = virgil.Keys.Generate(); - /// - /// - VirgilKey Generate(); - - /// - /// Loads the from current storage by specified key name. - /// - /// The name of the Key. - /// The Key password. - /// An instance of class. - /// - /// - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// var aliceKey = virgil.Keys.Load("[KEY_NAME]", "[OPTIONAL_KEY_PASSWORD]"); - /// - /// - VirgilKey Load(string keyName, string keyPassword = null); - - - /// - /// Imports the from buffer. - /// - /// The buffer with Key. - /// The Key password. - /// An instance of class. - /// - /// - /// var virgil = new VirgilApi(); - /// // initialize a buffer from base64 encoded string - /// var aliceKeyBuffer = VirgilBuffer.From( - /// "[BASE64_ENCODED_VIRGIL_KEY]", StringEncoding.Base64); - /// - /// // import Virgil Key from buffer - /// var aliceKey = virgil.Keys.Import(aliceKeyBuffer, "[OPTIONAL_KEY_PASSWORD]"); - /// - /// - VirgilKey Import(VirgilBuffer keyBuffer, string keyPassword = null); - - /// - /// Removes the from the storage. - /// - /// - /// - /// var virgil = new VirgilApi(); - /// virgil.Destroy("[VIRGIL_KEY_NAME]"); - /// - /// - void Destroy(string keyName); - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IVirgilApi.cs b/SDK/Source/Virgil.SDK.Shared/IVirgilApi.cs deleted file mode 100644 index 06124ac9..00000000 --- a/SDK/Source/Virgil.SDK.Shared/IVirgilApi.cs +++ /dev/null @@ -1,58 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - /// - /// The interface defines a high-level API that provides easy access to - /// Virgil Security services and allows to perform cryptographic operations by using two domain entities - /// and . Where the is an entity - /// that represents a user's Private key, and the is the entity that represents - /// user's identity and a Public key. - /// - public interface IVirgilApi - { - /// - /// Gets an instances of the class that provides a work with entities. - /// - IKeysManager Keys { get; } - - /// - /// Gets an instances of the class that provides a work with entities. - /// - ICardsManager Cards { get; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityValidationToken.cs b/SDK/Source/Virgil.SDK.Shared/IdentityValidationToken.cs deleted file mode 100644 index e76e7db8..00000000 --- a/SDK/Source/Virgil.SDK.Shared/IdentityValidationToken.cs +++ /dev/null @@ -1,51 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - /// - /// The repreents an information about identity and - /// token that allows to execture action that requires identity authentication, like global - /// Card creation or global Card revocation. - /// - public class IdentityValidationToken - { - /// - /// Gets the validation token value. - /// - public string Value { get; internal set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityVerificationAttempt.cs b/SDK/Source/Virgil.SDK.Shared/IdentityVerificationAttempt.cs deleted file mode 100644 index 79fcdf4d..00000000 --- a/SDK/Source/Virgil.SDK.Shared/IdentityVerificationAttempt.cs +++ /dev/null @@ -1,101 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Threading.Tasks; - - /// - /// The class providesd information about identity verification process. - /// - public class IdentityVerificationAttempt - { - private readonly VirgilApiContext context; - - /// - /// Initializes a new instance of the class. - /// - internal IdentityVerificationAttempt(VirgilApiContext context) - { - this.context = context; - } - - /// - /// Gets the operation action ID. - /// - public Guid ActionId { get; internal set; } - - /// - /// Gets the identity value. - /// - public string Identity { get; internal set; } - - /// - /// Gets the type of the identity. - /// - public string IdentityType { get; internal set; } - - /// - /// Gets the time to live. - /// - public TimeSpan TimeToLive { get; internal set; } - - /// - /// Gets a key/value dictionary with user fields. - /// - public int CountToLive { get; internal set; } - - /// - /// Confirms an identity and generates a validation token that can be used to perform operations like - /// Publish and Revoke global Cards. - /// - /// The confirmation - /// A new instance of class. - public async Task ConfirmAsync(IdentityConfirmation confirmation) - { - var emailConfirmation = confirmation as EmailConfirmation; - - if (emailConfirmation == null) - throw new NotSupportedException(); - - var validationToken = await confirmation.ConfirmAndGrabValidationTokenAsync(this, this.context.Client) - .ConfigureAwait(false); - - return new IdentityValidationToken { Value = validationToken }; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityVerificationOptions.cs b/SDK/Source/Virgil.SDK.Shared/IdentityVerificationOptions.cs deleted file mode 100644 index 98f7fa62..00000000 --- a/SDK/Source/Virgil.SDK.Shared/IdentityVerificationOptions.cs +++ /dev/null @@ -1,76 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Collections.Generic; - - /// - /// The class provides additional options - /// for verification 's identity. - /// - public class IdentityVerificationOptions - { - public IdentityVerificationOptions() - { - TimeToLive = TimeSpan.FromSeconds(3600); - CountToLive = 1; - ExtraFields = new Dictionary(); - - } - /// - /// Gets or sets a key/value dictionary that represents a user fields. In some cases it could be necessary - /// to pass some parameters to verification server and receive them back in an email. For this special - /// case an optional dictionary property can be used. If type of an - /// identity is email, all values passed in will be passed back in an email in a - /// hidden form with extra hidden fields. - /// - public IDictionary ExtraFields { get; set; } - - /// - /// Gets or sets the "time to live" value is used to limit the lifetime of the token in - /// seconds (maximum value is 60 * 60 * 24 * 365 = 1 year). Default value is 3600. - /// - public TimeSpan TimeToLive { get; set; } - - /// - /// Gets or sets the "count to live" parameter is used to restrict the number of validation token - /// usages (maximum value is 100). - /// - public int CountToLive { get; set; } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/KeysManager.cs b/SDK/Source/Virgil.SDK.Shared/KeysManager.cs deleted file mode 100644 index 6860b936..00000000 --- a/SDK/Source/Virgil.SDK.Shared/KeysManager.cs +++ /dev/null @@ -1,117 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - - using Virgil.SDK.Exceptions; - - /// - /// The class provides a list of methods to generate the s - /// and further them storage in secure place. - /// - internal class KeysManager : IKeysManager - { - private readonly VirgilApiContext context; - - /// - /// Initializes a new instance of the class. - /// - public KeysManager(VirgilApiContext context) - { - this.context = context; - } - - /// - /// Generates a new with default parameters. - /// - public VirgilKey Generate() - { - var keyPair = this.context.Crypto.GenerateKeys(); - return new VirgilKey(this.context, keyPair.PrivateKey); - } - - /// - /// Loads the from current storage by specified key name. - /// - /// The name of the Key. - /// The Key password. - /// An instance of class. - /// - /// - public VirgilKey Load(string keyName, string keyPassword = null) - { - if (string.IsNullOrWhiteSpace(keyName)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(keyName)); - - if (!this.context.KeyStorage.Exists(keyName)) - throw new VirgilKeyIsNotFoundException(); - - var entry = this.context.KeyStorage.Load(keyName); - var privateKey = this.context.Crypto.ImportPrivateKey(entry.Value, keyPassword); - - var virgilKey = new VirgilKey(this.context, privateKey); - - return virgilKey; - } - - /// - /// Imports the from buffer. - /// - /// The buffer with Key. - /// The Key password. - /// An instance of class. - public VirgilKey Import(VirgilBuffer keyBuffer, string keyPassword = null) - { - var privateKey = this.context.Crypto.ImportPrivateKey(keyBuffer.GetBytes(), keyPassword); - var virgilKey = new VirgilKey(this.context, privateKey); - - return virgilKey; - } - - /// - /// Removes the from the storage. - /// - public void Destroy(string keyName) - { - if (string.IsNullOrWhiteSpace(keyName)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(keyName)); - - this.context.KeyStorage.Delete(keyName); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Localization.Designer.cs b/SDK/Source/Virgil.SDK.Shared/Localization.Designer.cs deleted file mode 100644 index 1f9de496..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Localization.Designer.cs +++ /dev/null @@ -1,263 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Virgil.SDK { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Localization { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Localization() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Virgil.SDK.Localization", typeof(Localization).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Argument is null or whitespace. - /// - internal static string ExceptionArgumentIsNullOrWhitespace { - get { - return ResourceManager.GetString("ExceptionArgumentIsNullOrWhitespace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Domain value specified for the domain identity is invalid. - /// - internal static string ExceptionDomainValueDomainIdentityIsInvalid { - get { - return ResourceManager.GetString("ExceptionDomainValueDomainIdentityIsInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Identity verification request is not sent. - /// - internal static string ExceptionIdentityVerificationIsNotSent { - get { - return ResourceManager.GetString("ExceptionIdentityVerificationIsNotSent", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key pair with specified name is already exists.. - /// - internal static string ExceptionKeyPairAlreadyExistsException { - get { - return ResourceManager.GetString("ExceptionKeyPairAlreadyExistsException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key pair is not found. - /// - internal static string ExceptionKeyPairNotFound { - get { - return ResourceManager.GetString("ExceptionKeyPairNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key pair parameters is not valid.. - /// - internal static string ExceptionKeyPairParametersIsNotValid { - get { - return ResourceManager.GetString("ExceptionKeyPairParametersIsNotValid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Public Key is not found. - /// - internal static string ExceptionPublicKeyNotFound { - get { - return ResourceManager.GetString("ExceptionPublicKeyNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String can not be empty. - /// - internal static string ExceptionStringCanNotBeEmpty { - get { - return ResourceManager.GetString("ExceptionStringCanNotBeEmpty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to String parameter should have length less than {0}. - /// - internal static string ExceptionStringLengthIsInvalid { - get { - return ResourceManager.GetString("ExceptionStringLengthIsInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User data with same fields is already exists.. - /// - internal static string ExceptionUserDataAlreadyExists { - get { - return ResourceManager.GetString("ExceptionUserDataAlreadyExists", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Data class specified is invalid. - /// - internal static string ExceptionUserDataClassSpecifiedIsInvalid { - get { - return ResourceManager.GetString("ExceptionUserDataClassSpecifiedIsInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Data confirmation entity not found. - /// - internal static string ExceptionUserDataConfirmationEntityNotFound { - get { - return ResourceManager.GetString("ExceptionUserDataConfirmationEntityNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Data confirmation identityInfo invalid. - /// - internal static string ExceptionUserDataConfirmationTokenInvalid { - get { - return ResourceManager.GetString("ExceptionUserDataConfirmationTokenInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Data integrity constraint violation. - /// - internal static string ExceptionUserDataIntegrityConstraintViolation { - get { - return ResourceManager.GetString("ExceptionUserDataIntegrityConstraintViolation", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The user data is not confirmed yet. - /// - internal static string ExceptionUserDataIsNotConfirmedYet { - get { - return ResourceManager.GetString("ExceptionUserDataIsNotConfirmedYet", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User data is not found. - /// - internal static string ExceptionUserDataNotFound { - get { - return ResourceManager.GetString("ExceptionUserDataNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The user data value is required. - /// - internal static string ExceptionUserDataValueIsRequired { - get { - return ResourceManager.GetString("ExceptionUserDataValueIsRequired", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Data was already confirmed and does not need further confirmation. - /// - internal static string ExceptionUserDataWasAlreadyConfirmed { - get { - return ResourceManager.GetString("ExceptionUserDataWasAlreadyConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This user id had been confirmed earlier. - /// - internal static string ExceptionUserIdHadBeenConfirmed { - get { - return ResourceManager.GetString("ExceptionUserIdHadBeenConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User info data validation failed. - /// - internal static string ExceptionUserInfoDataValidationFailed { - get { - return ResourceManager.GetString("ExceptionUserInfoDataValidationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The Access Token is not provider.. - /// - internal static string ExceptionVirgilServiceNotInitialized { - get { - return ResourceManager.GetString("ExceptionVirgilServiceNotInitialized", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The Access Token is not provider.. - /// - internal static string ExceptionVirgilConfigIsNotInitialized - { - get - { - return ResourceManager.GetString("ExceptionVirgilConfigIsNotInitialized", resourceCulture); - } - } - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/Localization.resx b/SDK/Source/Virgil.SDK.Shared/Localization.resx deleted file mode 100644 index b484df5c..00000000 --- a/SDK/Source/Virgil.SDK.Shared/Localization.resx +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Public Key is not found - - - String can not be empty - - - User data with same fields is already exists. - - - User data is not found - - - User Data integrity constraint violation - - - User Data confirmation entity not found - - - User Data confirmation identityInfo invalid - - - User Data was already confirmed and does not need further confirmation - - - User Data class specified is invalid - - - Domain value specified for the domain identity is invalid - - - This user id had been confirmed earlier - - - The user data is not confirmed yet - - - The user data value is required - - - User info data validation failed - - - String parameter should have length less than {0} - - - Identity verification request is not sent - - - The Access Token is not provider. - - - Argument is null or whitespace - - - The key pair with specified name is already exists. - - - The key pair is not found - - - The key pair parameters is not valid. - - - The VirgilConfig is not initialized. Please call Initialize method to setup HighLevel components. - - \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Signer/ModelSigner.cs b/SDK/Source/Virgil.SDK.Shared/Signer/ModelSigner.cs new file mode 100644 index 00000000..cc3c83c2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Signer/ModelSigner.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using Virgil.CryptoAPI; +using Virgil.SDK.Common; +using Virgil.SDK.Web; + +namespace Virgil.SDK.Signer +{ + /// + /// The class provides signing operation for . + /// + public class ModelSigner + { + public readonly ICardCrypto Crypto; + public const string SelfSigner = "self"; + public const string VirgilSigner = "virgil"; + + + public ModelSigner(ICardCrypto crypto) + { + this.Crypto = crypto; + } + + /// + /// Adds owner's signature to the specified using specified signer + /// parameters included private key and additional raw bytes. + /// + /// the instance of to be signed. + /// the instance of to sign with. + /// Some additional raw bytes to be signed with model. + public void SelfSign(RawSignedModel model, IPrivateKey signerPrivateKey, byte[] signatureSnapshot = null) + { + ValidateSignParams(model, signerPrivateKey); + + Sign(model, + new SignParams() + { + SignerPrivateKey = signerPrivateKey, + Signer = SelfSigner + }, + signatureSnapshot + ); + } + + + /// /// + /// Adds owner's signature to the specified using specified signer + /// parameters included private key and dictionary with additional data. + /// + /// the instance of to be signed. + /// the instance of to sign with. + /// Dictionary with additional data to be signed with model. + public void SelfSign(RawSignedModel model, IPrivateKey signerPrivateKey, Dictionary extraFields) + { + SelfSign(model, signerPrivateKey, + (extraFields != null) ? SnapshotUtils.TakeSnapshot(extraFields) : null + ); + } + + private static void ValidateSignParams(RawSignedModel model, IPrivateKey signerPrivateKey) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + + + if (signerPrivateKey == null) + { + throw new ArgumentException($"{nameof(signerPrivateKey)} property is mandatory"); + } + } + + /// + /// Adds signature to the specified using specified signer + /// parameters included private key, signer type and additional raw bytes. + /// + /// the instance of to be signed. + /// the instance of to sign with. + /// Some additional raw bytes to be signed with model. + public void Sign(RawSignedModel model, SignParams @params, byte[] signatureSnapshot = null) + { + ValidateExtendedSignParams(model, @params); + ThrowExceptionIfSignatureExists(@params, model.Signatures); + + var extendedSnapshot = signatureSnapshot != null ? + Bytes.Combine(model.ContentSnapshot, signatureSnapshot) + : model.ContentSnapshot; + + var signatureBytes = Crypto.GenerateSignature(extendedSnapshot, @params.SignerPrivateKey); + + var signature = new RawSignature + { + Signer = @params.Signer, + Signature = signatureBytes, + Snapshot = signatureSnapshot + }; + model.Signatures.Add(signature); + } + + private static void ThrowExceptionIfSignatureExists(SignParams @params, IList signatures) + { + if (signatures != null && + ((List)signatures).Exists( + s => s.Signer == @params.Signer)) + { + throw new VirgilException("The model already has this signature."); + } + } + + /// + /// Adds signature to the specified using specified signer + /// parameters included private key, signer type and dictionary with additional data. + /// + /// the instance of to be signed. + /// the instance of to sign with. + /// Dictionary with additional data to be signed with model. + public void Sign(RawSignedModel model, SignParams @params, Dictionary ExtraFields) + { + Sign(model, @params, + (ExtraFields != null) ? SnapshotUtils.TakeSnapshot(ExtraFields) : null + ); + } + + private static void ValidateExtendedSignParams(RawSignedModel model, SignParams @params) + { + ValidateSignParams(model, @params.SignerPrivateKey); + + if (@params.Signer == null) + { + throw new ArgumentException($"{nameof(@params.Signer)} property is mandatory"); + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyStorageException.cs b/SDK/Source/Virgil.SDK.Shared/Signer/SignParams.cs similarity index 76% rename from SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyStorageException.cs rename to SDK/Source/Virgil.SDK.Shared/Signer/SignParams.cs index 289f3ad4..9878a4ab 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/KeyStorageException.cs +++ b/SDK/Source/Virgil.SDK.Shared/Signer/SignParams.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,20 +34,26 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Exceptions +using Virgil.CryptoAPI; +using Virgil.SDK.Web; + +namespace Virgil.SDK.Signer { /// - /// Represents errors occurred during interaction with cryptographic keys storage. + /// The class is used for + /// specifying parameters. /// - /// - public class KeyStorageException : VirgilException + public class SignParams { /// - /// Initializes a new instance of the class. + /// Gets or sets the signer's private key. /// - /// The message. - public KeyStorageException(string message) : base(message) - { - } + public IPrivateKey SignerPrivateKey { get; set; } + + /// + /// Gets or sets the sign's type. + /// + public string Signer { get; set; } + } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Contracts/Storage/KeyEntry.cs b/SDK/Source/Virgil.SDK.Shared/Storage/KeyEntry.cs similarity index 91% rename from SDK/Source/Virgil.SDK.Contracts/Storage/KeyEntry.cs rename to SDK/Source/Virgil.SDK.Shared/Storage/KeyEntry.cs index 6ccccf84..fdefd8f0 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Storage/KeyEntry.cs +++ b/SDK/Source/Virgil.SDK.Shared/Storage/KeyEntry.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,11 +33,10 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion +using System.Collections.Generic; namespace Virgil.SDK.Storage { - using System.Collections.Generic; - /// /// Represents a key pair storage entry. /// @@ -56,6 +55,6 @@ public class KeyEntry /// /// Gets or sets the meta data associated with key pair. /// - public IDictionary MetaData { get; set; } + public IDictionary Meta { get; set; } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Storage/KeyStorage.cs b/SDK/Source/Virgil.SDK.Shared/Storage/KeyStorage.cs new file mode 100644 index 00000000..8195abab --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Storage/KeyStorage.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.SDK.Storage +{ + /// + /// The provides protected storage using the user + /// credentials to encrypt or decrypt keys. + /// + public class KeyStorage + { + private readonly SecureStorage coreStorage; + + /// + /// Initializes a new instance of the class. + /// + public KeyStorage(string password) + { + coreStorage = new SecureStorage(password); + // if (Environment.OSVersion.ToString().ToLower().Contains("windows") || + // Environment.OSVersion.ToString().ToLower().Contains("droid") + // ){ + + // } + } + + /// + /// Stores the specified instance of . + /// + /// The instance of . + /// + public void Store(KeyEntry entry) + { + if (entry == null) + { + throw new ArgumentNullException(nameof(entry)); + } + var keyEntryData = Encoding.UTF8.GetBytes( + Configuration.Serializer.Serialize( + new KeyEntryData() {Meta = entry.Meta, Value = entry.Value} + )); + coreStorage.Save(entry.Name, keyEntryData); + } + + /// + /// Loads the instance of associated with the given alias. + /// + /// The alias name. + /// + /// + /// The requested key, or null if the given alias does not exist or does + /// not identify a key-related entry. + /// + public KeyEntry Load(string name) + { + var keyEntryData = coreStorage.Load(name); + var keyEntryJson = Encoding.UTF8.GetString(keyEntryData); + var keyEntryObject = Configuration.Serializer.Deserialize(keyEntryJson); + + return new KeyEntry + { + Name = name, + Value = keyEntryObject.Value, + Meta = keyEntryObject.Meta + }; + } + + /// + /// Checks if the given alias exists in this keystore. + /// + /// The alias name. + public bool Exists(string name) + { + return coreStorage.Exists(name); + } + + /// + /// Delete the instance of by the given name. + /// + /// The alias name. + /// + public void Delete(string name) + { + coreStorage.Delete(name); + } + + /// + /// Returns the list of aliases that are kept in the storage. + /// + public string[] Names() + { + return coreStorage.Aliases(); + } + + } + + internal class KeyEntryData + { + [DataMember(Name = "value")] + public byte[] Value { get; set; } + + [DataMember(Name = "meta_data")] + public IDictionary Meta { get; set; } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Storage/PrivateKeyStorage.cs b/SDK/Source/Virgil.SDK.Shared/Storage/PrivateKeyStorage.cs new file mode 100644 index 00000000..fa67afe8 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Storage/PrivateKeyStorage.cs @@ -0,0 +1,121 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections.Generic; +using Virgil.CryptoAPI; + +namespace Virgil.SDK.Storage +{ + public class PrivateKeyStorage + { + private readonly KeyStorage keyStorage; + private readonly IPrivateKeyExporter privateKeyExporter; + + /// + /// Initializes a new instance of the class. + /// + /// The instance of that is + /// used for private key export/import. + /// Password for storage. + public PrivateKeyStorage(IPrivateKeyExporter keyExporter, string password = null) + { + privateKeyExporter = keyExporter; + keyStorage = new KeyStorage(password); + } + + /// + /// Stores the private key to the given alias. + /// + /// The private key. + /// The alias. + /// Some additional data. + /// + public void Store(IPrivateKey privateKey, string alias, IDictionary meta = null) + { + var keyEntry = new KeyEntry() + { + Meta = meta, + Name = alias, + Value = privateKeyExporter.ExportPrivatekey(privateKey) + }; + this.keyStorage.Store(keyEntry); + } + + /// + /// Checks if the private key exists in this storage by given alias. + /// + /// The alias. + /// true if the key data exists, false otherwise + public bool Exists(string alias) + { + return keyStorage.Exists(alias); + } + + /// + /// Loads the private key associated with the given alias. + /// + /// The alias. + /// + /// The requested private key and its additional data, or exception if the given key does not exist. + /// + /// + public Tuple> Load(string alias) + { + var keyEntry = this.keyStorage.Load(alias); + var key = privateKeyExporter.ImportPrivateKey(keyEntry.Value); + return new Tuple>(key, keyEntry.Meta); + } + + /// + /// Delete key and its additional data by the alias in this storage. + /// + /// The alias. + /// + public void Delete(string alias) + { + this.keyStorage.Delete(alias); + } + + /// + /// Returns the list of aliases that are kept in the storage. + /// + public string[] Aliases() + { + return keyStorage.Names(); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestModel.cs b/SDK/Source/Virgil.SDK.Shared/Verification/CardVerificationException.cs similarity index 82% rename from SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestModel.cs rename to SDK/Source/Virgil.SDK.Shared/Verification/CardVerificationException.cs index 74e15ad0..9b6bb11e 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/TransferObjects/SignableRequestModel.cs +++ b/SDK/Source/Virgil.SDK.Shared/Verification/CardVerificationException.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,16 +34,17 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Verification { - using Newtonsoft.Json; - - internal class SignableRequestModel + /// + /// Represents errors occurred during card validation. + /// + public class CardVerificationException : VirgilException { - [JsonProperty("content_snapshot")] - public byte[] ContentSnapshot { get; set; } + public CardVerificationException(string message) + : base(message) + { + } - [JsonProperty("meta")] - public SignableRequestMetaModel Meta { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Verification/ICardVerifier.cs b/SDK/Source/Virgil.SDK.Shared/Verification/ICardVerifier.cs new file mode 100644 index 00000000..8d92867e --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Verification/ICardVerifier.cs @@ -0,0 +1,16 @@ +namespace Virgil.SDK.Verification +{ + /// + /// The provides interface + /// for card verification process. + /// + public interface ICardVerifier + { + /// + /// Verify the specified card. + /// + /// The instance of to be verified. + /// True if card is verified, False otherwise + bool VerifyCard(Card card); + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/RecipientsNotFoundException.cs b/SDK/Source/Virgil.SDK.Shared/Verification/VerifierCredentials.cs similarity index 78% rename from SDK/Source/Virgil.SDK.Shared/Exceptions/RecipientsNotFoundException.cs rename to SDK/Source/Virgil.SDK.Shared/Verification/VerifierCredentials.cs index 3ae6adb0..81629f2c 100644 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/RecipientsNotFoundException.cs +++ b/SDK/Source/Virgil.SDK.Shared/Verification/VerifierCredentials.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,18 +34,22 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Exceptions +namespace Virgil.SDK.Verification { /// - /// Represents an error that occurs when recipient's Card(s) isn't found on Virgil Services. + /// The class provides + /// a signer's identifier and its public key in base64. /// - public class RecipientsNotFoundException : VirgilApiException + public class VerifierCredentials { /// - /// Initializes a new instance of the class. + /// Gets or sets a signer's identifier. /// - public RecipientsNotFoundException() : base("Recipient Card(s) isn't found.") - { - } + public string Signer { get; set; } + + /// + /// Gets or sets a signer's public key in base64. + /// + public string PublicKeyBase64 { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Verification/VirgilCardVerifier.cs b/SDK/Source/Virgil.SDK.Shared/Verification/VirgilCardVerifier.cs new file mode 100644 index 00000000..a01beed2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Verification/VirgilCardVerifier.cs @@ -0,0 +1,202 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Virgil.SDK.Signer; +using System.Collections.Generic; +using System.Linq; +using Virgil.CryptoAPI; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Verification +{ + /// + /// The represents card verification process. + /// + public class VirgilCardVerifier : ICardVerifier + { + private List whiteLists; + private readonly ICardCrypto cardCrypto; + private string VirgilPublicKeyBase64 = "MCowBQYDK2VwAyEAljOYGANYiVq1WbvVvoYIKtvZi2ji9bAhxyu6iV/LF8M="; + + /// + /// Initializes a new instance of the class. + /// + /// The instance of that is + /// used for signature verification. + public VirgilCardVerifier(ICardCrypto crypto) + { + this.whiteLists = new List(); + this.cardCrypto = crypto; + this.VerifySelfSignature = true; + this.VerifyVirgilSignature = true; + } + + /// + /// Verify self signature if true. + /// + public bool VerifySelfSignature { get; set; } + + /// + /// Verify virgil signature if true. + /// + public bool VerifyVirgilSignature { get; set; } + + /// + /// List with collections of that are used for verification. + /// + /// Card is verified successfully only if + /// it contains verified signature by at least one virefier from each Whitelist. + public IEnumerable Whitelists + { + get => this.whiteLists; + set + { + this.whiteLists.Clear(); + + if (value != null) + { + this.whiteLists.AddRange(value); + } + } + } + /// + /// To verify the specified card. + /// + /// The instance of to verify. + /// True is card is verified according to set rules, otherwise False. + /// To set up rule for verification of self signature use . + /// To set up rule for verification of virgil service signature use . + /// To set up Whitelists use . + public bool VerifyCard(Card card) + { + if (this.VerifySelfSignature && + !ValidateSignerSignature(card, card.PublicKey, ModelSigner.SelfSigner)) + { + return false; + } + + if (this.VerifyVirgilSignature && + !ValidateSignerSignature( + card, + this.GetPublicKey(VirgilPublicKeyBase64), + ModelSigner.VirgilSigner)) + { + return false; + } + + if (!this.whiteLists.Any()) + { + return true; + } + + // select a signers from card signatures. + var signers = card.Signatures.Select(x => x.Signer); + + var verifiersCredentialsLists = whiteLists + .Select(s => s.VerifiersCredentials); + + foreach (var verifiersCredentials in verifiersCredentialsLists) + { + // if whitelist doesn't have credentials then + //this is to be regarded as a violation of the policy. + if (verifiersCredentials == null || !verifiersCredentials.Any()) + { + return false; + } + var intersectedCreds = verifiersCredentials.Where(x => signers.Contains(x.Signer)); + + // if card doesn't contain signature from AT LEAST one verifier from a Whitelist then + //this is to be regarded as a violation of the policy (at least one). + if (!intersectedCreds.Any()) + { + return false; + } + foreach (var intersectedCred in intersectedCreds) + { + var signerPublicKey = this.GetPublicKey(intersectedCred.PublicKeyBase64); + if (ValidateSignerSignature(card, signerPublicKey, intersectedCred.Signer)) + { + break; + } + if (intersectedCred == intersectedCreds.Last()) + { + return false; + } + } + } + return true; + } + + private IPublicKey GetPublicKey(string signerPublicKeyBase64) + { + var publicKeyBytes = Bytes.FromString(signerPublicKeyBase64, StringEncoding.BASE64); + var publicKey = cardCrypto.ImportPublicKey(publicKeyBytes); + + return publicKey; + } + + + private bool ValidateSignerSignature(Card card, + IPublicKey signerPublicKey, string signerType) + { + var signature = card.Signatures.SingleOrDefault( + s => s.Signer == signerType); + // validate verifier's signature + + if (signature != null) + { + var extendedSnapshot = signature.Snapshot != null + ? Bytes.Combine(card.ContentSnapshot, signature.Snapshot) + : card.ContentSnapshot; + + if (cardCrypto.VerifySignature( + signature.Signature, + extendedSnapshot, + signerPublicKey)) + { + return true; + } + } + + return false; + } + + internal void ChangeServiceCreds(string publicKey) + { + this.VirgilPublicKeyBase64 = publicKey; + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Verification/WhiteList.cs b/SDK/Source/Virgil.SDK.Shared/Verification/WhiteList.cs new file mode 100644 index 00000000..08a95e50 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Verification/WhiteList.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace Virgil.SDK.Verification +{ + /// + /// The implements a collection of + /// that is used for card verification in . + /// + public class Whitelist + { + private List verifiersCredentials; + + /// + /// Initializes a new instance of the class. + /// + public Whitelist() + { + verifiersCredentials = new List(); + } + + /// + /// Gets or sets the collection of + /// that is used for card verification in . + /// + public IEnumerable VerifiersCredentials + { + get => this.verifiersCredentials; + set + { + this.verifiersCredentials.Clear(); + + if (value != null) + { + this.verifiersCredentials.AddRange(value); + } + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.projitems b/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.projitems index 09ebb14b..563b798a 100644 --- a/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.projitems +++ b/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.projitems @@ -6,109 +6,68 @@ 6e4fe86f-7862-4fd9-b2e3-b73ae0957eb6 - Virgil.SDK.Shared + Virgil.SDK - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Localization.resx - True - True - - - - - - - - - - - - - - - - - IdentityVerificationOptions.cs - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Localization.Designer.cs - ResXFileCodeGenerator - + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.shproj b/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.shproj index aea7bcae..c1776c0e 100644 --- a/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.shproj +++ b/SDK/Source/Virgil.SDK.Shared/Virgil.SDK.Shared.shproj @@ -8,6 +8,12 @@ + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoApi + + - + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilApi.cs b/SDK/Source/Virgil.SDK.Shared/VirgilApi.cs deleted file mode 100644 index 814755bd..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilApi.cs +++ /dev/null @@ -1,124 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - - /// - /// The class is a high-level API that provides easy access to - /// Virgil Security services and allows to perform cryptographic operations by using two domain entities - /// and . Where the is an entity - /// that represents a user's Private key, and the is the entity that represents - /// user's identity and a Public key. - /// - public class VirgilApi : IVirgilApi - { - private readonly VirgilApiContext context; - - private readonly Lazy lazyKeysManager; - private readonly Lazy lazyCardsManager; - - /// - /// Initializes a new instance of the class. - /// - /// The access token. - /// - /// Initializes a new instance for actions: get card, find card. - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// - /// - public VirgilApi(string accessToken) - : this(new VirgilApiContext { AccessToken = accessToken }) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Initializes a new instance for actions with global cards. - /// - /// var virgilApi = new VirgilApi(); - /// - /// - public VirgilApi() - : this(new VirgilApiContext { AccessToken = null }) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The configuration. - /// - /// Initializes a new instance for actions: publish card, revoke card. - /// - /// var virgil = new VirgilApi(new VirgilApiContext - /// { - /// AccessToken = "[YOUR_ACCESS_TOKEN_HERE]", - /// Credentials = new AppCredentials - /// { - /// AppId = "[YOUR_APP_ID_HERE]", - /// AppKey = VirgilBuffer.FromFile("[YOUR_APP_KEY_FILEPATH_HERE]"), - /// AppKeyPassword = "[YOUR_APP_KEY_PASSWORD_HERE]", - /// } - /// }); - /// - /// - public VirgilApi(VirgilApiContext context) - { - if (context == null) - throw new ArgumentNullException(nameof(context)); - - this.context = context; - - this.lazyKeysManager = new Lazy(() => new KeysManager(this.context)); - this.lazyCardsManager = new Lazy(() => new CardsManager(this.context)); - } - - /// - /// Gets an instances of the class that provides a work with entities. - /// - public IKeysManager Keys => this.lazyKeysManager.Value; - - /// - /// Gets an instances of the class that provides a work with entities. - /// - public ICardsManager Cards => this.lazyCardsManager.Value; - } -} diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilApiContext.cs b/SDK/Source/Virgil.SDK.Shared/VirgilApiContext.cs deleted file mode 100644 index ef9e87bf..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilApiContext.cs +++ /dev/null @@ -1,217 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Collections.Generic; - using System.Linq; - - using Virgil.SDK.Common; - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - using Virgil.SDK.Device; - using Virgil.SDK.Storage; - - /// - /// The class manages the dependencies during run time. - /// It also contains a list of preperties that uses to configurate the high-level components. - /// - public partial class VirgilApiContext - { - private ICrypto customCrypto; - private IKeyStorage customStorage; - private IDeviceManager customDevice; - - private readonly Lazy lazyCrypto; - private readonly Lazy lazyStorage; - private readonly Lazy lazyDevice; - private readonly Lazy lazyClient; - - /// - /// Initializes a new instance of the class. - /// - public VirgilApiContext() - { - this.UseBuiltInVerifiers = true; - this.lazyCrypto = new Lazy(this.InitCrypto); - this.lazyStorage = new Lazy(this.InitStorage); - this.lazyDevice = new Lazy(this.InitDeviceManager); - this.lazyClient = new Lazy(this.InitClient); - } - - /// - /// Gets or sets the access token provides an authenticated secure access to the - /// Virgil Security services. The access token also allows the API to associate - /// your app requests with your Virgil Security developer’s account. It's not required if - /// has been set. - /// - public string AccessToken { get; set; } - - /// - /// Gets or sets the application authentication credentials. - /// - public Credentials Credentials { get; set; } - - /// - /// Gets or sets a list of Virgil Card verifiers. - /// - public IEnumerable CardVerifiers { get; set; } - - /// - /// Gets or sets the client parameters. - /// - public VirgilClientParams ClientParams { get; set; } - - /// - /// Gets or sets the indicator whether the Cards be verified with built in verifiers or not. - /// - public bool UseBuiltInVerifiers { get; set; } - - /// - /// Gets a crypto API that represents a set of methods for dealing with low-level - /// cryptographic primitives and algorithms. - /// - internal ICrypto Crypto => this.lazyCrypto.Value; - - /// - /// Gets a cryptographic keys storage. - /// - internal IKeyStorage KeyStorage => this.lazyStorage.Value; - - /// - /// Gets the instance that represents an infirmation about current device. - /// - internal IDeviceManager DeviceManager => this.lazyDevice.Value; - - /// - /// Gets a Virgil Security services client. - /// - internal VirgilClient Client => this.lazyClient.Value; - - /// - /// Gets the request signer. - /// - internal IRequestSigner RequestSigner => new RequestSigner(this.Crypto); - - /// - /// Sets a crypto API that represents a set of methods for dealing with low-level - /// cryptographic primitives and algorithms. - /// - public void SetCrypto(ICrypto crypto) - { - if (crypto == null) - throw new ArgumentNullException(nameof(crypto)); - - if (this.lazyCrypto.IsValueCreated) - throw new NotSupportedException(); - - this.customCrypto = crypto; - } - - /// - /// Sets a cryptographic keys storage. - /// - public void SetKeyStorage(IKeyStorage keyStorage) - { - if (keyStorage == null) - throw new ArgumentNullException(nameof(keyStorage)); - - if (this.lazyStorage.IsValueCreated) - throw new NotSupportedException(); - - this.customStorage = keyStorage; - } - - /// - /// Sets a manager that provides an infirmation about current device. - /// - public void SetDeviceManager(IDeviceManager deviceManager) - { - if (deviceManager == null) - throw new ArgumentNullException(nameof(deviceManager)); - - if (this.lazyDevice.IsValueCreated) - throw new NotSupportedException(); - - this.customDevice = deviceManager; - } - - #region Private Methods - - private ICrypto InitCrypto() - { - return this.customCrypto ?? new VirgilCrypto(); - } - - private VirgilClient InitClient() - { - var client = this.ClientParams == null - ? new VirgilClient(this.AccessToken) - : new VirgilClient(this.ClientParams); - - var validator = new CardValidator(this.Crypto); - - if (this.UseBuiltInVerifiers) - { - validator.AddDefaultVerifiers(); - } - - if (this.CardVerifiers != null && this.CardVerifiers.Any()) - { - foreach (var verifierInfo in this.CardVerifiers) - { - validator.AddVerifier(verifierInfo.CardId, verifierInfo.PublicKeyData.GetBytes()); - } - } - - client.SetCardValidator(validator); - return client; - } - - private IKeyStorage InitStorage() - { - return this.customStorage ?? this.GetDefaultKeyStorage(); - } - - private IDeviceManager InitDeviceManager() - { - return this.customDevice ?? this.GetDefaultDeviceManager(); - } - - #endregion - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilBuffer.cs b/SDK/Source/Virgil.SDK.Shared/VirgilBuffer.cs deleted file mode 100644 index 38152c31..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilBuffer.cs +++ /dev/null @@ -1,206 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - - /// - /// The class provides a list of methods that - /// simplify the work with an array of bytes. - /// - public partial class VirgilBuffer - { - private readonly byte[] bytes; - - /// - /// Initializes a new instance of the class. - /// - /// The array of bytes. - internal VirgilBuffer(byte[] bytes) - { - if (bytes == null) - throw new ArgumentNullException(nameof(bytes)); - - if (bytes.Length == 0) - throw new ArgumentException(@"Argument is empty collection", nameof(bytes)); - - this.bytes = bytes; - } - - /// - /// Gets an array of bytes. - /// - /// A byte array - public byte[] GetBytes() - { - return this.bytes; - } - - /// - /// Creates a new containing the given string. If provided, the encoding parameter - /// identifies the character encoding of string. - /// - /// String to encode. - /// The encoding of string. - /// - /// null - public static VirgilBuffer From(string str, StringEncoding encoding = StringEncoding.Utf8) - { - switch (encoding) - { - case StringEncoding.Base64: - return FromBase64String(str); - case StringEncoding.Hex: - return FromHEXString(str); - case StringEncoding.Utf8: - return FromUTF8String(str); - default: - throw new ArgumentOutOfRangeException(nameof(encoding), encoding, null); - } - } - - /// - /// Allocates a new using an array of bytes. - /// - /// An array of bytes to copy from. - /// A new instance of class - public static VirgilBuffer From(byte[] bytes) - { - return new VirgilBuffer(bytes); - } - - /// - /// Decodes the current to a string according to the UTF8 character encoding. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - return this.ToString(StringEncoding.Utf8); - } - - /// - /// Decodes the current to a string according to the specified - /// character encoding in . - /// - /// The character encoding to decode to. - /// - /// A that represents this instance. - /// - /// null - public string ToString(StringEncoding encoding) - { - switch (encoding) - { - case StringEncoding.Base64: - return this.ToBase64String(); - case StringEncoding.Hex: - return this.ToHEXString(); - case StringEncoding.Utf8: - return this.ToUTF8String(); - default: - throw new ArgumentOutOfRangeException(nameof(encoding), encoding, null); - } - } - - /// - /// Initializes a new buffer from specified string, which encodes binary data as base-64 digits. - /// - /// A new instance of class. - private static VirgilBuffer FromBase64String(string str) - { - return new VirgilBuffer(Convert.FromBase64String(str)); - } - - /// - /// Initializes a new buffer from specified string, which encodes binary data as utf-8. - /// - /// A new instance of class. - private static VirgilBuffer FromUTF8String(string str) - { - return new VirgilBuffer(System.Text.Encoding.UTF8.GetBytes(str)); - } - - /// - /// Initializes a new buffer from specified string, which encodes binary data as hexadecimal digits. - /// - /// A new instance of class. - private static VirgilBuffer FromHEXString(string str) - { - var numberChars = str.Length; - var bytes = new byte[numberChars / 2]; - - for (var i = 0; i < numberChars; i += 2) - { - bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16); - } - - return new VirgilBuffer(bytes); - } - - /// - /// Converts all the bytes in current buffer to its equivalent string representation that - /// is encoded with base-64 digits. - /// - /// The string representation of current buffer bytes. - private string ToBase64String() - { - return Convert.ToBase64String(this.bytes); - } - - /// - /// Decodes all the bytes in current buffer into a string. - /// - /// A string that contains the results of decoding the specified sequence of bytes. - private string ToUTF8String() - { - return System.Text.Encoding.UTF8.GetString(this.bytes); - } - - /// - /// Converts the numeric value of each element of a current buffer bytes to its - /// equivalent hexadecimal string representation. - /// - /// The string representation of current buffer bytes - private string ToHEXString() - { - var hex = BitConverter.ToString(this.bytes); - return hex.Replace("-", "").ToLower(); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilBufferExtensions.cs b/SDK/Source/Virgil.SDK.Shared/VirgilBufferExtensions.cs deleted file mode 100644 index 08bad28f..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilBufferExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System.Threading.Tasks; - - /// - /// Provides useful extension methods for class. - /// - public static class VirgilBufferExtensions - { - /// - /// Decodes the current to a string according to the specified - /// character encoding in . - /// - /// The task - /// The character encoding to decode to. - /// - /// A that represents this instance. - /// - public static Task ToString(this Task task, StringEncoding encoding) - { - return task.ContinueWith(t => t.Result.ToString(encoding)); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilCard.cs b/SDK/Source/Virgil.SDK.Shared/VirgilCard.cs deleted file mode 100644 index ce6f8448..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilCard.cs +++ /dev/null @@ -1,288 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - - using Virgil.SDK.Common; - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - using Exceptions; - - /// - /// A Virgil Card is the main entity of the Virgil Security services, it includes an information - /// about the user and his public key. The Virgil Card identifies the user by one of his available - /// types, such as an email, a phone number, etc. - /// - public sealed class VirgilCard - { - private readonly VirgilApiContext context; - private readonly CardModel card; - - /// - /// Initializes a new instance of the class. - /// - internal VirgilCard(VirgilApiContext context, CardModel card) - { - this.context = context; - this.card = card; - - this.PublicKey = this.context.Crypto.ImportPublicKey(this.card.SnapshotModel.PublicKeyData); - } - - /// - /// Gets the unique identifier for the Virgil Card. - /// - public string Id => this.card.Id; - - /// - /// Gets the value of current Virgil Card identity. - /// - public string Identity => this.card.SnapshotModel.Identity; - - /// - /// Gets the identityType of current Virgil Card identity. - /// - public string IdentityType => this.card.SnapshotModel.IdentityType; - - /// - /// Gets the custom parameters. - /// - public IReadOnlyDictionary CustomFields => this.card.SnapshotModel.Data; - - /// - /// Gets a Public key that is assigned to current . - /// - internal IPublicKey PublicKey { get; } - - /// - /// Encrypts the specified data for current recipient. - /// - /// The data to be encrypted. - /// - /// - /// // search for Virgil Cards - /// var aliceCards = await virgil.Cards.FindAsync("alice"); - /// - /// var fileBuf = VirgilBuffer.FromFile("FILE_NAME_HERE"); - /// - /// // encrypt the buffer using found Virgil Cards - /// var cipherFileBuf = aliceCards.Encrypt(fileBuf); - /// - /// - public VirgilBuffer Encrypt(VirgilBuffer buffer) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - var cipherdata = this.context.Crypto.Encrypt(buffer.GetBytes(), this.PublicKey); - return new VirgilBuffer(cipherdata); - } - - /// - /// Verifies the specified buffer and signature with current recipient. - /// - /// The data to be verified. - /// The signature used to verify the data integrity. - public bool Verify(VirgilBuffer buffer, VirgilBuffer signature) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); - - if (signature == null) - throw new ArgumentNullException(nameof(signature)); - - var isValid = this.context.Crypto.Verify( - buffer.GetBytes(), signature.GetBytes(), this.PublicKey); - - return isValid; - } - - /// - /// Exports a current instance into base64 encoded string. - /// - /// A string that represents a . - /// - /// - /// // export a Virgil Card to string - /// var exportedAliceCard = aliceCard.Export(); - /// - /// - /// How to get aliceCard - public string Export() - { - var serializedCard = JsonSerializer.Serialize(this.card); - return VirgilBuffer.From(serializedCard).ToString(StringEncoding.Base64); - } - - /// - /// Initiates an identity verification process for current Card indentity type. It is only working for - /// Global identity types like Email. - /// - /// An instance of that contains - /// information about operation etc... - /// Find the usage at the example - public async Task CheckIdentityAsync(IdentityVerificationOptions options = null) - { - var actionId = await this.context.Client - .VerifyIdentityAsync(this.Identity, this.IdentityType, options?.ExtraFields) - .ConfigureAwait(false); - - var attempt = new IdentityVerificationAttempt(this.context) - { - ActionId = actionId, - TimeToLive = options?.TimeToLive ?? TimeSpan.FromSeconds(3600), - CountToLive = options?.CountToLive ?? 1, - IdentityType = this.IdentityType, - Identity = this.Identity - }; - - return attempt; - } - - /// - /// Publishes a current to the Virgil Security services. - /// - /// - /// - /// // import a Virgil Card from string - /// var importedCard = virgil.Cards.Import(exportedCard); - /// - /// // publish a Virgil Card - /// await virgil.Cards.PublishAsync(importedCard); - /// - /// - /// How to get exportedCard - internal async Task PublishAsync() - { - if ((this.context == null) || (this.context.Credentials == null) || - (this.context.Credentials.GetAppId() == null) || - (this.context.Credentials.GetAppKey(context.Crypto) == null)) - { - throw new AppCredentialsException(); - } - var publishCardRequest = new PublishCardRequest(this.card.Snapshot, this.card.Meta.Signatures); - - var appId = this.context.Credentials.GetAppId(); - var appKey = this.context.Credentials.GetAppKey(this.context.Crypto); - - var requestSigner = new RequestSigner(this.context.Crypto); - requestSigner.AuthoritySign(publishCardRequest, appId, appKey); - - var updatedModel = await this.context.Client - .PublishCardAsync(publishCardRequest).ConfigureAwait(false); - - this.card.Meta = updatedModel.Meta; - } - - /// - /// Publishes a current to the Virgil Security services into global scope. - /// - /// - /// - /// // generate a Virgil Key - /// var aliceKey = virgil.Keys.Generate(); - /// - /// // save the Virgil Key into storage - /// aliceKey.Save("[KEY_NAME]", "[KEY_PASSWORD]"); - /// - /// // create a Global Virgil Card - /// var aliceCard = virgil.Cards.CreateGlobal( - /// identity: "alice@virgilsecurity.com", - /// identityType: IdentityType.Email, - /// ownerKey: aliceKey - /// ); - /// // initiate identity verification process - /// var attempt = await aliceCard.CheckIdentityAsync(); - /// - /// // confirm an identity and grab the validation token - /// var token = await attempt.ConfirmAsync(new EmailConfirmation("[CONFIRMATION_CODE]")); - /// - /// // publish the Virgil Card - /// await aliceCard.PublishAsGlobalAsync(token); - /// - /// - internal async Task PublishAsGlobalAsync(IdentityValidationToken identityToken) - { - if (identityToken == null) - throw new ArgumentNullException(nameof(identityToken)); - - if (this.card.SnapshotModel.Scope != CardScope.Global) - throw new NotSupportedException(); - - var publishCardRequest = new PublishGlobalCardRequest(this.card.Snapshot, - identityToken.Value, this.card.Meta.Signatures); - - var updatedModel = await this.context.Client - .PublishGlobalCardAsync(publishCardRequest).ConfigureAwait(false); - - this.card.Meta = updatedModel.Meta; - } - - /// - /// Encrypts a buffer data for list of Cards. - /// - /// A new with encrypted data. - internal VirgilBuffer Encrypt(VirgilBuffer buffer, IEnumerable recipients) - { - var publicKeyRecipients = new List(); - var virgilCards = recipients?.ToList(); - - if (virgilCards != null) - { - publicKeyRecipients.AddRange(virgilCards.Select(r => r.PublicKey)); - } - - var cipherdata = this.context.Crypto.Encrypt(buffer.GetBytes(), publicKeyRecipients.ToArray()); - return new VirgilBuffer(cipherdata); - } - - /// - /// To check if current Virgil Card was generated for . - /// - /// An instance of . - public bool IsPairFor(VirgilKey virgilKey) - { - return this.PublicKey.Get().Value.SequenceEqual(virgilKey.ExportPublicKey().GetBytes()); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilCardExtensions.cs b/SDK/Source/Virgil.SDK.Shared/VirgilCardExtensions.cs deleted file mode 100644 index 7e9744bc..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilCardExtensions.cs +++ /dev/null @@ -1,386 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - - using Virgil.SDK.Exceptions; - - /// - /// Provides useful extension methods for class. - /// - public static class VirgilCardExtensions - { - #region SignThenEncrypt - - /// - /// Encrypts and signs the specified buffer with data for current enumeration of recipients. - /// - /// The list of recipients. - /// The buffer data to be encrypted. - /// The signer's - /// A new with encrypted data. - /// - public static Task SignThenEncrypt(this Task> task, VirgilBuffer buffer, VirgilKey key) - { - return task.ContinueWith(t => - { - if (t.Exception == null && !t.Result.Any()) - { - throw new RecipientsNotFoundException(); - } - - return key.SignThenEncrypt(buffer, t.Result); - }); - } - - /// - /// Encrypts and signs the specified plaintext for current enumeration of recipients. - /// - /// The list of recipients. - /// The plaintext to be encrypted. - /// The signer's - /// A new with encrypted data. - /// - public static Task SignThenEncrypt(this Task> task, string plaintext, VirgilKey key) - { - return SignThenEncrypt(task, VirgilBuffer.From(plaintext), key); - } - - /// - /// Encrypts and signs the specified data for current enumeration of recipients. - /// - /// The list of recipients. - /// The data to be encrypted. - /// The signer's - /// A new with encrypted data. - /// - public static Task SignThenEncrypt(this Task> task, byte[] data, VirgilKey key) - { - return SignThenEncrypt(task, VirgilBuffer.From(data), key); - } - - /// - /// Encrypts the specified data for current recipient. - /// - /// The recipient - /// The buffer with data to be encrypted. - /// The signer's key. - /// - /// A new with encrypted data. - /// - /// - public static Task SignThenEncrypt(this Task task, VirgilBuffer buffer, VirgilKey key) - { - return task.ContinueWith(t => key.SignThenEncrypt(buffer, new[] { t.Result })); - } - - /// - /// Encrypts the specified plaintext for current recipient. - /// - /// The recipient - /// The plaintext to be encrypted. - /// The signer's key. - /// - /// A new with encrypted data. - /// - /// - public static Task SignThenEncrypt(this Task task, string plaintext, VirgilKey key) - { - return SignThenEncrypt(task, VirgilBuffer.From(plaintext), key); - } - - /// - /// Encrypts the specified data for current recipient. - /// - /// The recipient - /// The data to be encrypted. - /// The signer's key. - /// - /// A new with encrypted data. - /// - /// - public static Task SignThenEncrypt(this Task task, byte[] data, VirgilKey key) - { - return SignThenEncrypt(task, VirgilBuffer.From(data), key); - } - - #endregion - - #region Encrypt - - /// - /// Encrypts the specified buffer data for list of recipients. - /// - /// The list of recipients. - /// The buffer data to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task> task, VirgilBuffer buffer) - { - return task.ContinueWith(t => - { - if (t.Exception == null && !t.Result.Any()) - { - throw new RecipientsNotFoundException(); - } - - return t.Result.Encrypt(buffer); - }); - } - - /// - /// Encrypts the specified plaintext for list of recipients. - /// - /// The list of recipients. - /// The plaintext to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task> task, string plaintext) - { - return Encrypt(task, VirgilBuffer.From(plaintext)); - } - - /// - /// Encrypts the specified buffer data for list of recipients. - /// - /// The list of recipients. - /// The byte array data to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task> task, byte[] data) - { - return Encrypt(task, VirgilBuffer.From(data)); - } - - /// - /// Encrypts the specified buffer with data for current recipient. - /// - /// The recipient - /// The buffer with data to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task task, VirgilBuffer buffer) - { - return task.ContinueWith(t => t.Result.Encrypt(buffer)); - } - - /// - /// Encrypts the plaintext for current recipient. - /// - /// The recipient - /// The plaintext to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task task, string plaintext) - { - return Encrypt(task, VirgilBuffer.From(plaintext)); - } - - /// - /// Encrypts the specified data for current recipient. - /// - /// The recipient - /// The data to be encrypted. - /// A new with encrypted data. - /// - public static Task Encrypt(this Task task, byte[] data) - { - return Encrypt(task, VirgilBuffer.From(data)); - } - - /// - /// Encrypts the specified text for list of Cards. - /// - /// The list of recipients. - /// The buffer data to be encrypted. - /// A new with encrypted data. - /// - public static VirgilBuffer Encrypt(this IEnumerable recipients, string plaintext) - { - if (string.IsNullOrWhiteSpace(plaintext)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(plaintext)); - - return Encrypt(recipients, VirgilBuffer.From(plaintext)); - } - - /// - /// Encrypts the specified bytes for list of Cards. - /// - /// The list of recipients. - /// The buffer data to be encrypted. - /// A new with encrypted data. - /// - public static VirgilBuffer Encrypt(this IEnumerable recipients, byte[] bytes) - { - if (recipients == null) - throw new ArgumentNullException(nameof(recipients)); - - return Encrypt(recipients, new VirgilBuffer(bytes)); - } - - /// - /// Encrypts the specified buffer data for list of Cards. - /// - /// The list of recipients. - /// The buffer data to be encrypted. - /// A new with encrypted data. - /// - public static VirgilBuffer Encrypt(this IEnumerable recipients, VirgilBuffer buffer) - { - if (recipients == null) - throw new ArgumentNullException(nameof(recipients)); - - var virgilCards = recipients.ToList(); - return virgilCards.First().Encrypt(buffer, virgilCards); - } - - /// - /// Encrypts the specified text for Card. - /// - /// The list of recipients. - /// The plaintext to be encrypted. - /// A new with encrypted data. - /// - public static VirgilBuffer Encrypt(this VirgilCard recipient, string plaintext) - { - if (string.IsNullOrWhiteSpace(plaintext)) - throw new ArgumentException(Localization.ExceptionArgumentIsNullOrWhitespace, nameof(plaintext)); - - return recipient.Encrypt(VirgilBuffer.From(plaintext)); - } - - /// - /// Encrypts the specified text for Card. - /// - /// The list of recipients. - /// The byte array to be encrypted. - /// A new with encrypted data. - /// - public static VirgilBuffer Encrypt(this VirgilCard recipient, byte[] bytes) - { - return recipient.Encrypt(new VirgilBuffer(bytes)); - } - - #endregion - - #region Verify - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The text. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static Task Verify(this Task task, VirgilBuffer buffer, VirgilBuffer signature) - { - return task.ContinueWith(t => t.Result.Verify(buffer, signature)); - } - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The text. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static Task Verify(this Task task, string text, VirgilBuffer signature) - { - return Verify(task, VirgilBuffer.From(text), signature); - } - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The data to be signed. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static Task Verify(this Task task, byte[] data, VirgilBuffer signature) - { - return Verify(task, VirgilBuffer.From(data), signature); - } - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The text. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static bool Verify(this VirgilCard recipient, string text, VirgilBuffer signature) - { - return Verify(recipient, VirgilBuffer.From(text), signature); - } - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The data to be signed. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static bool Verify(this VirgilCard recipient, byte[] data, VirgilBuffer signature) - { - return Verify(recipient, VirgilBuffer.From(data), signature); - } - - /// - /// Verifies that a digital signature is valid for specified text. - /// - /// The recipient. - /// The text. - /// The signature. - /// true if the signature is valid; otherwise, false. - /// - public static bool Verify(this VirgilCard recipient, VirgilBuffer buffer, VirgilBuffer signature) - { - return recipient.Verify(buffer, signature); - } - - #endregion - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityTypeExtensiosn.cs b/SDK/Source/Virgil.SDK.Shared/VirgilException.cs old mode 100644 new mode 100755 similarity index 84% rename from SDK/Source/Virgil.SDK.Shared/IdentityTypeExtensiosn.cs rename to SDK/Source/Virgil.SDK.Shared/VirgilException.cs index 595ab140..01cf3b67 --- a/SDK/Source/Virgil.SDK.Shared/IdentityTypeExtensiosn.cs +++ b/SDK/Source/Virgil.SDK.Shared/VirgilException.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -38,11 +38,13 @@ namespace Virgil.SDK { using System; - internal static class IdentityTypeExtensiosn + /// + /// Represents errors occurred during interaction with SDK components. + /// + public class VirgilException : Exception { - public static string ToFriendlyString(this IdentityType identityType) + public VirgilException(string message) : base(message) { - return Enum.GetName(typeof(IdentityType), identityType)?.ToLower(); } } -} +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilKey.cs b/SDK/Source/Virgil.SDK.Shared/VirgilKey.cs deleted file mode 100644 index 8a589280..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilKey.cs +++ /dev/null @@ -1,240 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System; - using System.Collections.Generic; - using System.Linq; - - using Virgil.SDK.Storage; - using Virgil.SDK.Exceptions; - using Virgil.SDK.Cryptography; - - /// - /// The class represents a user's high-level Private key which provides - /// a list of methods that allows to store the key and perform cryptographic operations like - /// Decrypt, Sign etc. - /// - public sealed class VirgilKey - { - private readonly VirgilApiContext context; - private readonly IPrivateKey privateKey; - - /// - /// Prevents a default instance of the class from being created. - /// - internal VirgilKey(VirgilApiContext context, IPrivateKey privateKey) - { - this.context = context; - this.privateKey = privateKey; - } - - - /// - /// Exports the to default format, specified in Crypto API. - /// - /// - /// - /// var exportedAliceKey = aliceKey.Export("[OPTIONAL_KEY_PASSWORD]") - /// .ToString(StringEncoding.Base64); - /// - /// - /// How to get aliceKey - public VirgilBuffer Export(string password = null) - { - var exportedPrivateKey = this.context.Crypto.ExportPrivateKey(this.privateKey, password); - return new VirgilBuffer(exportedPrivateKey); - } - - - /// - /// Generates a digital signature for specified data using current . - /// - /// The data for which the digital signature will be generated. - /// A new buffer that containing the result from performing the operation. - /// - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// // load Virgil Key - /// var aliceKey = virgil.Keys.Load("[KEY_NAME]", "[KEY _PASSWORD]"); - /// // prepare a message - /// var message = "Hey Bob, hope you are doing well."; - /// - /// // generate signature - /// var signature = aliceKey.Sign(message); - /// - /// - public VirgilBuffer Sign(VirgilBuffer data) - { - if (data == null) - throw new ArgumentNullException(nameof(data)); - - var signature = this.context.Crypto.Sign(data.GetBytes(), this.privateKey); - return new VirgilBuffer(signature); - } - - - /// - /// Decrypts the specified cipher data using . - /// - /// The encrypted data. - /// A byte array containing the result from performing the operation. - /// - /// - /// - /// // load a Virgil Key from device storage - /// var aliceKey = virgil.Keys.Load("[KEY_NAME]", "[OPTIONAL_KEY_PASSWORD]"); - /// - /// // decrypt a cipher buffer using loaded Virgil Key - /// var originalFileBuf = aliceKey.Decrypt(cipherFileBuf); - /// - /// - public VirgilBuffer Decrypt(VirgilBuffer cipherBuffer) - { - if (cipherBuffer == null) - throw new ArgumentNullException(nameof(cipherBuffer)); - - var data = this.context.Crypto.Decrypt(cipherBuffer.GetBytes(), this.privateKey); - return new VirgilBuffer(data); - } - - - /// - /// Encrypts and signs the data. - /// - /// The data to be encrypted. - /// The list of recipients. - /// The encrypted data - /// - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// // load a Virgil Key from device storage - /// var aliceKey = virgil.Keys.Load("[KEY_NAME]", "[OPTIONAL_KEY_PASSWORD]"); - /// - /// // search for Virgil Cards - /// var bobCards = await virgil.Cards.FindAsync("bob"); - /// - /// // prepare the message - /// var message = "Hey Bob, how's it going?"; - /// - /// // sign and encrypt the message - /// var ciphertext = aliceKey.SignThenEncrypt(message, bobCards) - /// .ToString(StringEncoding.Base64); - /// - /// - public VirgilBuffer SignThenEncrypt(VirgilBuffer buffer, IEnumerable recipients) - { - if (recipients == null) - throw new ArgumentNullException(nameof(recipients)); - - var publicKeys = recipients.Select(pk => pk.PublicKey).ToArray(); - var cipherdata = this.context.Crypto.SignThenEncrypt(buffer.GetBytes(), this.privateKey, publicKeys); - - return new VirgilBuffer(cipherdata); - } - - - /// - /// Decrypts and verifies the data. - /// - /// The data to be decrypted. - /// A list of trusted cards, which can contains the signer's . - /// The decrypted data, which is the original plain text before encryption. - /// - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// // load a Virgil Key from device storage - /// var bobKey = virgil.Keys.Load("[KEY_NAME]", "[OPTIONAL_KEY_PASSWORD]") - /// - /// // get a sender's Virgil Card - /// var aliceCard = await virgil.Cards.Get("[ALICE_CARD_ID]") - /// - /// // decrypt the message - /// var originalMessage = bobKey.DecryptThenVerify(ciphertext, aliceCard).ToString(); - /// - /// - public VirgilBuffer DecryptThenVerify(VirgilBuffer cipherbuffer, params VirgilCard[] cards) - { - var plaitext = this.context.Crypto - .DecryptThenVerify(cipherbuffer.GetBytes(), this.privateKey, cards.Select(it => it.PublicKey).ToArray()); - - return new VirgilBuffer(plaitext); - } - - /// - /// Saves a current in secure storage. - /// - /// The name of the key. - /// The password (optional). - /// - /// - /// var virgil = new VirgilApi("[YOUR_ACCESS_TOKEN_HERE]"); - /// aliceKey.Save("[KEY_NAME]", "[OPTIONAL_KEY_PASSWORD]"); - /// - /// - /// How to get aliceKey - public VirgilKey Save(string keyName, string password = null) - { - var exportedPrivateKey = this.context.Crypto.ExportPrivateKey(this.privateKey, password); - var keyEntry = new KeyEntry - { - Name = keyName, - Value = exportedPrivateKey - }; - - if (this.context.KeyStorage.Exists(keyEntry.Name)) - throw new VirgilKeyIsAlreadyExistsException(); - - this.context.KeyStorage.Store(keyEntry); - return this; - } - - - /// - /// Exports the Public key value from current . - /// - /// A new that contains Public Key value. - public VirgilBuffer ExportPublicKey() - { - var publicKey = this.context.Crypto.ExtractPublicKey(this.privateKey); - return VirgilBuffer.From(this.context.Crypto.ExportPublicKey(publicKey)); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/VirgilKeyExtensions.cs b/SDK/Source/Virgil.SDK.Shared/VirgilKeyExtensions.cs deleted file mode 100644 index 540427ff..00000000 --- a/SDK/Source/Virgil.SDK.Shared/VirgilKeyExtensions.cs +++ /dev/null @@ -1,152 +0,0 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. -// -// Lead Maintainer: Virgil Security Inc. -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// (1) Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// (2) Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in -// the documentation and/or other materials provided with the -// distribution. -// -// (3) Neither the name of the copyright holder nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -#endregion - -namespace Virgil.SDK -{ - using System.Collections.Generic; - - /// - /// Provides useful extension methods for class. - /// - public static class VirgilKeyExtensions - { - /// - /// Signs a byte array data using current and then encrypt it - /// using multiple recipient's s. - /// - /// The used to sign the . - /// The data to be encrypted. - /// A list of recipient's s used to - /// encrypt the . - /// A new instance with encrypted data. - public static VirgilBuffer SignThenEncrypt(this VirgilKey virgilKey, byte[] data, IEnumerable recipients) - { - return virgilKey.SignThenEncrypt(VirgilBuffer.From(data), recipients); - } - - /// - /// Signs a plaintext using current and then encrypt it - /// using multiple recipient's s. - /// - /// The used to sign the . - /// The plaintext to be encrypted. - /// A list of recipient's s used to - /// encrypt the . - /// A new instance with encrypted data. - public static VirgilBuffer SignThenEncrypt(this VirgilKey virgilKey, string plaintext, IEnumerable recipients) - { - return virgilKey.SignThenEncrypt(VirgilBuffer.From(plaintext), recipients); - } - - /// - /// Signs a byte array data using current and then encrypt it - /// using recipient's . - /// - /// The used to sign the . - /// The plaintext to be encrypted. - /// The recipient's used to - /// encrypt the . - /// A new instance with encrypted data. - public static VirgilBuffer SignThenEncrypt(this VirgilKey virgilKey, byte[] data, VirgilCard recipient) - { - return virgilKey.SignThenEncrypt(VirgilBuffer.From(data), new[] { recipient }); - } - - /// - /// Signs the plaintext using current and then encrypt it - /// using recipient's . - /// - /// The used to sign the . - /// The plaintext to be encrypted. - /// The recipient's used to - /// encrypt the . - /// A new instance with encrypted data. - public static VirgilBuffer SignThenEncrypt(this VirgilKey virgilKey, string plaintext, VirgilCard recipient) - { - return virgilKey.SignThenEncrypt(VirgilBuffer.From(plaintext), new []{ recipient }); - } - - /// - /// Decrypts a ciphertext using current and verifies one - /// using specified . - /// - /// The , that represents a Private key. - /// The ciphertext in base64 encoded string. - /// The signer's , that represents a - /// Public key and user/device information. - /// A new instance with decrypted data. - public static VirgilBuffer DecryptThenVerify(this VirgilKey virgilKey, byte[] cipherdata, VirgilCard signerCard) - { - return virgilKey.DecryptThenVerify(new VirgilBuffer(cipherdata), signerCard); - } - - /// - /// Decrypts a ciphertext using current and verifies one - /// using specified . - /// - /// The , that represents a Private key. - /// The ciphertext in base64 encoded string. - /// The signer's , that represents a - /// Public key and user/device information. - /// A new instance with decrypted data. - public static VirgilBuffer DecryptThenVerify(this VirgilKey virgilKey, string ciphertext, VirgilCard signerCard) - { - return virgilKey.DecryptThenVerify(VirgilBuffer.From(ciphertext, StringEncoding.Base64), signerCard); - } - - /// - /// Signs a plaintext using current . - /// - /// The used to sign the - /// The plaintext to be signed. - /// A new instance with generated signature. - public static VirgilBuffer Sign(this VirgilKey virgilKey, string plaintext) - { - return virgilKey.Sign(VirgilBuffer.From(plaintext)); - } - - /// - /// Signs a byte array data using current . - /// - /// The used to sign the - /// The plaintext to be signed. - /// A new instance with generated signature. - public static VirgilBuffer Sign(this VirgilKey virgilKey, byte[] data) - { - return virgilKey.Sign(VirgilBuffer.From(data)); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Common/RequestSigner.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/CallbackJwtProvider.cs similarity index 52% rename from SDK/Source/Virgil.SDK.Shared/Common/RequestSigner.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Authorization/CallbackJwtProvider.cs index 170f1046..f45bf590 100644 --- a/SDK/Source/Virgil.SDK.Shared/Common/RequestSigner.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/CallbackJwtProvider.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,54 +33,49 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion +using System; +using System.Threading.Tasks; -namespace Virgil.SDK.Common +namespace Virgil.SDK.Web.Authorization { - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - /// - /// The class provides methods for signing requests. + /// The class provides an opportunity to + /// get access token using callback mechanism. /// - public class RequestSigner : IRequestSigner + public class CallbackJwtProvider : IAccessTokenProvider { - private readonly ICrypto crypto; - /// - /// Initializes a new instance of the class. + /// Callback, that takes an instance of + /// and returns string representation of + /// generated instance of >. /// - public RequestSigner(ICrypto crypto) - { - this.crypto = crypto; - } - + public readonly Func> ObtainAccessTokenFunction; /// - /// Sign passed request with private key. + /// Initializes a new instance of the class. /// - /// request for signing. - /// private key to sign with. - public void SelfSign(ISignableRequest request, IPrivateKey privateKey) + /// async function, that takes an instance of + /// and returns string representation of + /// generated instance of >. + public CallbackJwtProvider(Func> obtainTokenFunc) { - var fingerprint = this.crypto.CalculateFingerprint(request.Snapshot); - var signature = this.crypto.Sign(fingerprint.GetValue(), privateKey); - - request.AppendSignature(fingerprint.ToHEX(), signature); + this.ObtainAccessTokenFunction = obtainTokenFunc ?? + throw new ArgumentNullException(nameof(obtainTokenFunc)); } - /// - /// Sign passed request with authority private key. + /// Gets access token. /// - /// request for signing. - /// authority id. - /// authority private key to sign with. - public void AuthoritySign(ISignableRequest request, string appId, IPrivateKey appKey) + /// The instance of . + /// The instance of . + public async Task GetTokenAsync(TokenContext context) { - var fingerprint = this.crypto.CalculateFingerprint(request.Snapshot); - var signature = this.crypto.Sign(fingerprint.GetValue(), appKey); - - request.AppendSignature(appId, signature); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + var jwt = await this.ObtainAccessTokenFunction.Invoke(context); + return new Jwt(jwt); } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/ConstAccessTokenProvider.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/ConstAccessTokenProvider.cs new file mode 100644 index 00000000..7a0b4f20 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/ConstAccessTokenProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// The class provides an opportunity to + /// use constant access token. + /// + public class ConstAccessTokenProvider : IAccessTokenProvider + { + private readonly IAccessToken accessToken; + + /// + /// Initializes a new instance of the class. + /// + /// an instance of + public ConstAccessTokenProvider(IAccessToken accessToken) + { + this.accessToken = accessToken ?? throw new ArgumentNullException(nameof(accessToken)); + } + + /// + /// Gets access token. + /// + /// can be null as it does not affect the result. + /// the specified token in the + /// constructor . + public Task GetTokenAsync(TokenContext context=null) + { + Func> obtainToken = async () => + { + return accessToken; + }; + return obtainToken.Invoke(); + + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessToken.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessToken.cs new file mode 100644 index 00000000..18ed8b88 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessToken.cs @@ -0,0 +1,50 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion +namespace Virgil.SDK.Web.Authorization +{ + /// + /// The provides interface + /// for access token. + /// + public interface IAccessToken + { + // Gets token identity. + string Identity(); + + // Gets token string representation. + string ToString(); + } +} diff --git a/SDK/Source/Virgil.SDK.Contracts/Exceptions/CryptoException.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessTokenProvider.cs similarity index 76% rename from SDK/Source/Virgil.SDK.Contracts/Exceptions/CryptoException.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessTokenProvider.cs index b04e0bc3..def7afe9 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Exceptions/CryptoException.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/IAccessTokenProvider.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,20 +34,22 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Exceptions +using System.Collections; +using System.Threading.Tasks; + +namespace Virgil.SDK.Web.Authorization { /// - /// Represents an errors occurred during interaction with crypto API. + /// The provides interface + /// to get access token. /// - /// - public class CryptoException : VirgilException + public interface IAccessTokenProvider { /// - /// Initializes a new instance of the class. + /// Gets access token. /// - /// The message. - public CryptoException(string message) : base(message) - { - } + /// The instance of . + /// The instance of . + Task GetTokenAsync(TokenContext context); } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JWT.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JWT.cs new file mode 100644 index 00000000..61cdab35 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JWT.cs @@ -0,0 +1,172 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion +using System; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// The class implements interface + /// in terms of Virgil JWT. + /// + public class Jwt : IAccessToken + { + /// + /// Gets a jwt header. + /// + public readonly JwtHeaderContent HeaderContent; + + /// + /// Gets a jwt body. + /// + public readonly JwtBodyContent BodyContent; + + /// + /// Gets a digital signature of jwt. + /// + public readonly byte[] SignatureData; + + private readonly string stringRepresentation; + private readonly byte[] unsignedData; + + + /// + /// Initializes a new instance of the class using specified header, body and signature. + /// + /// jwt header, an instance of . + /// jwt body, an instance of . + /// jwt signature data. + public Jwt( + JwtHeaderContent jwtHeaderContent, + JwtBodyContent jwtBodyContent, + byte[] signatureData + ) + { + BodyContent = jwtBodyContent ?? throw new ArgumentNullException(nameof(jwtBodyContent)); + HeaderContent = jwtHeaderContent ?? throw new ArgumentNullException(nameof(jwtHeaderContent)); + SignatureData = signatureData; + var withoutSignature = this.HeaderBase64() + "." + this.BodyBase64(); + unsignedData = Bytes.FromString(withoutSignature); + stringRepresentation = withoutSignature; + if (this.SignatureData != null) + { + stringRepresentation += "." + this.SignatureBase64(); + } + } + + /// + /// Initializes a new instance of the class using its string representation. + /// + /// string representation of signed jwt. It must be equal to: + /// base64UrlEncode(JWT Header) + "." + base64UrlEncode(JWT Body) "." + base64UrlEncode(Jwt Signature). + /// + public Jwt(string jwtStr) + { + var parts = jwtStr.Split(new char[] { '.' }); + if (parts.Length != 3) + { + throw new ArgumentException("Wrong JWT format."); + } + try + { + var headerJson = Bytes.ToString(Base64Url.Decode(parts[0])); + HeaderContent = Configuration.Serializer.Deserialize(headerJson); + var bodyJson = Bytes.ToString(Base64Url.Decode(parts[1])); + BodyContent = Configuration.Serializer.Deserialize(bodyJson); + SignatureData = Base64Url.Decode(parts[2]); + } + catch (Exception) + { + throw new ArgumentException("Wrong JWT format."); + } + + BodyContent.AppId = BodyContent.Issuer.Clone().ToString().Replace(JwtBodyContent.SubjectPrefix, ""); + BodyContent.Identity = BodyContent.Subject.Clone().ToString().Replace(JwtBodyContent.IdentityPrefix, ""); + unsignedData = Bytes.FromString(parts[0] + "." + parts[1]); + stringRepresentation = jwtStr; + } + + /// + /// String representation of jwt. + /// + public override string ToString() + { + return stringRepresentation; + } + + /// + /// String representation of jwt without signature. + /// It equals to: + /// base64UrlEncode(JWT Header) + "." + base64UrlEncode(JWT Body) + /// + public byte[] Unsigned() + { + return unsignedData; + } + + /// + /// Whether or not token is expired. + /// + public bool IsExpired() + { + return DateTime.UtcNow >= this.BodyContent.ExpiresAt; + } + + private string HeaderBase64() + { + return Base64Url.Encode(Bytes.FromString(Configuration.Serializer.Serialize(this.HeaderContent))); + } + + private string BodyBase64() + { + return Base64Url.Encode(Bytes.FromString(Configuration.Serializer.Serialize(this.BodyContent))); + } + + private string SignatureBase64() + { + return Base64Url.Encode(this.SignatureData); + } + + /// + /// Jwt identity. + /// + /// + public string Identity() + { + return BodyContent.Identity; + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtBodyContent.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtBodyContent.cs new file mode 100644 index 00000000..8ab299e1 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtBodyContent.cs @@ -0,0 +1,147 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// represents content of . + /// + [DataContract] + public class JwtBodyContent + { + public const string IdentityPrefix = "identity-"; + public const string SubjectPrefix = "virgil-"; + + /// + /// Jwt application id. + /// + public string AppId { get; internal set; } + + /// + /// Jwt identity. + /// + public string Identity{ get; internal set; } + + /// + /// Jwt issuer. + /// + [DataMember(Name = "iss")] + public string Issuer { get; internal set; } + + /// + /// Jwt subject. + /// + [DataMember(Name = "sub")] + public string Subject { get; internal set; } + + /// + /// When Jwt was issued. + /// + [DataMember(Name = "iat")] + public DateTime IssuedAt { get; internal set; } + + /// + /// When Jwt will expire. + /// + [DataMember(Name = "exp")] + public DateTime ExpiresAt { get; internal set; } + + /// + /// Jwt additional data. + /// + [DataMember(Name = "ada")] + public Dictionary AdditionalData { get; internal set; } + + + /// + /// Initializes a new instance of the + /// + /// Application ID. Take it from + /// + /// identity (must be equal to RawSignedModel identity when publishing card) + /// issued data + /// expiration date + /// dictionary with additional data + public JwtBodyContent(string appId, + string identity, + DateTime issuedAt, + DateTime expiresAt, + Dictionary data) + { + ValidateParams(appId, identity, issuedAt, expiresAt); + + this.AppId = appId; + this.Identity = identity; + this.ExpiresAt = expiresAt; + this.IssuedAt = issuedAt; + this.Identity = identity; + this.AdditionalData = data; + this.Issuer = $"{SubjectPrefix}{AppId}"; + this.Subject = $"{IdentityPrefix}{Identity}"; + } + + private static void ValidateParams(string appId, string identity, DateTime issuedAt, DateTime expiresAt) + { + if (string.IsNullOrWhiteSpace(appId)) + { + throw new ArgumentNullException(nameof(appId)); + } + + if (string.IsNullOrWhiteSpace(identity)) + { + throw new ArgumentNullException(nameof(identity)); + } + + if (issuedAt == null) + { + throw new ArgumentNullException(nameof(issuedAt)); + } + if (expiresAt == null) + { + throw new ArgumentNullException(nameof(expiresAt)); + } + } + + internal JwtBodyContent() + { + } + } + +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtGenerator.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtGenerator.cs new file mode 100644 index 00000000..b261a2c2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtGenerator.cs @@ -0,0 +1,139 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion +using System; +using System.Collections.Generic; +using Virgil.CryptoAPI; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// The class implements generation. + /// + public class JwtGenerator + { + /// + /// Private Key which will be used for signing + /// enerated access tokens. + /// Take it on . + /// + public readonly IPrivateKey ApiKey; + + /// + /// Key Id of . + /// Take it on + /// + public readonly string ApiPublicKeyId; + + /// + /// Application id. + /// Take it on . + /// + public readonly string AppId; + + /// + /// Lifetime of generated tokens. + /// + public readonly TimeSpan LifeTime; + + /// + /// An instance of that is used to + /// generate token signature using . + /// + public readonly IAccessTokenSigner AccessTokenSigner; + + /// + /// Initializes a new instance of . + /// + /// Application id. Take it on + /// + /// Private Key which will be used for signing + /// enerated access tokens. Take it on + /// + /// Key Id of . + /// Take it on + /// + /// Lifetime of generated tokens. + /// + /// An instance of that is used to + /// generate token signature using . + public JwtGenerator( + string appId, + IPrivateKey apiKey, + string apiPublicKeyId, + TimeSpan lifeTime, + IAccessTokenSigner accessTokenSigner + ) + { + this.AppId = appId; + this.ApiKey = apiKey; + this.LifeTime = lifeTime; + this.ApiPublicKeyId = apiPublicKeyId; + this.AccessTokenSigner = accessTokenSigner; + } + + /// + /// Generates new JWT using specified identity and additional data. + /// + /// identity to generate with. + /// dictionary with additional data which will be kept in jwt body. + /// a new instanse of . + public Jwt GenerateToken(string identity, Dictionary data = null) + { + if (string.IsNullOrWhiteSpace(identity)) + { + throw new ArgumentException($"{nameof(identity)} property is mandatory"); + } + + //to truncate milliseconds and microseconds + var timeNow = DateTime.UtcNow; + var issuedAt = timeNow.AddTicks(-timeNow.Ticks % TimeSpan.TicksPerSecond); + var expiresAt = issuedAt.AddMilliseconds(LifeTime.TotalMilliseconds); + var jwtBody = new JwtBodyContent( + AppId, + identity, + issuedAt, + expiresAt, + data); + + var jwtHeader = new JwtHeaderContent(AccessTokenSigner.GetAlgorithm(), ApiPublicKeyId); + var unsignedJwt = new Jwt(jwtHeader, jwtBody, null); + var jwtBytes = Bytes.FromString(unsignedJwt.ToString()); + var signature = AccessTokenSigner.GenerateTokenSignature(jwtBytes, ApiKey); + return new Jwt(jwtHeader, jwtBody, signature); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtHeaderContent.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtHeaderContent.cs new file mode 100644 index 00000000..1a0cd861 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtHeaderContent.cs @@ -0,0 +1,113 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Runtime.Serialization; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// represents header of . + /// + [DataContract] + public class JwtHeaderContent + { + public const string VirgilContentType = "virgil-jwt;v=1"; + public const string JwtType = "JWT"; + + /// + /// Signature algorithm. + /// + [DataMember(Name = "alg")] + public string Algorithm { get; internal set; } + + /// + /// Access token type. + /// + [DataMember(Name = "typ")] + public string Type { get; internal set; } + + /// + /// Access token content type. + /// + [DataMember(Name = "cty")] + public string ContentType { get; internal set; } + + /// + /// Id of public key which is used for jwt signature verification. + /// + [DataMember(Name = "kid")] + public string KeyId { get; internal set; } + + /// + /// Initializes a new instance of the + /// + /// signature algorithm + /// API key id. Take it from + /// + public JwtHeaderContent( + string algorithm, + string keyId, + string type = JwtType, + string contentType = VirgilContentType) + { + ValidateParams(algorithm, keyId); + + this.Algorithm = algorithm; + this.KeyId = keyId; + this.Type = type; + this.ContentType = contentType; + } + + private static void ValidateParams(string algorithm, string apiKeyId) + { + if (string.IsNullOrWhiteSpace(algorithm)) + { + throw new ArgumentNullException(nameof(algorithm)); + } + + if (string.IsNullOrWhiteSpace(apiKeyId)) + { + throw new ArgumentNullException(nameof(apiKeyId)); + } + } + + internal JwtHeaderContent() + { + + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtVerifier.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtVerifier.cs new file mode 100644 index 00000000..379cbed4 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/JwtVerifier.cs @@ -0,0 +1,106 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using Virgil.CryptoAPI; + +namespace Virgil.SDK.Web.Authorization +{ + /// + /// The provides verification for . + /// + public class JwtVerifier + { + /// + /// An instance of that is used to + /// verify token signature. + /// + public readonly IAccessTokenSigner AccessTokenSigner; + + /// + /// Public Key which should be used to verify signatures + /// + public readonly IPublicKey ApiPublicKey; + + /// + /// Id of public key which should be used to verify signatures + /// + public readonly string ApiPublicKeyId; + + /// + /// Initializes a new instance of . + /// + /// An instance of that is used to + /// verify token signature. + /// Public Key which should be used to verify signatures + /// Id of public key which should be used to verify signatures + public JwtVerifier(IAccessTokenSigner accessTokenSigner, IPublicKey apiPublicKey, string apiPublicKeyId) + { + this.AccessTokenSigner = accessTokenSigner ?? throw new ArgumentNullException(nameof(accessTokenSigner)); + this.ApiPublicKey = apiPublicKey ?? throw new ArgumentNullException(nameof(apiPublicKey)); + + if (string.IsNullOrWhiteSpace(apiPublicKeyId)) + { + throw new ArgumentNullException(nameof(apiPublicKeyId)); + } + this.ApiPublicKeyId = apiPublicKeyId; + } + + /// + /// To verify specified token. + /// + /// An instance of to be virefied. + /// true if token is verified, otherwise false. + public bool VerifyToken(Jwt jwToken) + { + if (jwToken == null) + { + throw new ArgumentNullException(nameof(jwToken)); + } + if (jwToken.HeaderContent.KeyId != ApiPublicKeyId || + jwToken.HeaderContent.Algorithm != AccessTokenSigner.GetAlgorithm() || + jwToken.HeaderContent.ContentType != JwtHeaderContent.VirgilContentType || + jwToken.HeaderContent.Type != JwtHeaderContent.JwtType) + { + return false; + } + return this.AccessTokenSigner.VerifyTokenSignature( + jwToken.SignatureData, + jwToken.Unsigned(), + ApiPublicKey); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Storage/IKeyStorage.cs b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/TokenContext.cs similarity index 60% rename from SDK/Source/Virgil.SDK.Contracts/Storage/IKeyStorage.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Authorization/TokenContext.cs index 498fc2c1..8d23c566 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Storage/IKeyStorage.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Authorization/TokenContext.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,44 +33,34 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion - -namespace Virgil.SDK.Storage +namespace Virgil.SDK.Web.Authorization { - using Virgil.SDK.Exceptions; - /// - /// This interface describes a storage facility for cryptographic keys. + /// provides payload for + /// /// - public interface IKeyStorage + public class TokenContext { /// - /// Stores the key to the given alias. + ///Operation for which token is needed. /// - /// The key entry. - /// - void Store(KeyEntry keyEntry); + public readonly string Operation; /// - /// Loads the key associated with the given alias. + /// Identity that should be used in access token. /// - /// The name. - /// - /// The requested key, or null if the given alias does not exist or does - /// not identify a key-related entry. - /// - /// - KeyEntry Load(string keyName); + public readonly string Identity; /// - /// Checks if the key exists in this storage by given alias. + /// You can set up token cache in + /// and reset cached token if True. /// - /// The alias name. - /// true if the key exists, false otherwise - bool Exists(string keyName); + public readonly bool ForceReload; /// - /// Checks if the given alias exists in this keystore. + /// Initializes a new instance of the /// +<<<<<<< HEAD:SDK/Source/Virgil.SDK.Contracts/Storage/IKeyStorage.cs /// The alias name. /// void Delete(string keyName); @@ -79,5 +69,18 @@ public interface IKeyStorage /// Returns the list of keynames /// string[] Names(); +======= + /// Identity to use in token + /// Operation for which token is needed + /// If you set up token cache in + /// , + /// it should reset cached token and return new if TRUE. + public TokenContext(string identity, string operation, bool forceReload = false) + { + Operation = operation; + Identity = identity; + ForceReload = forceReload; + } +>>>>>>> v5:SDK/Source/Virgil.SDK.Shared/Web/Authorization/TokenContext.cs } } diff --git a/SDK/Source/Virgil.SDK.Shared/Web/CardClient.cs b/SDK/Source/Virgil.SDK.Shared/Web/CardClient.cs new file mode 100644 index 00000000..42ec6fbd --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/CardClient.cs @@ -0,0 +1,229 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Web +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + using Virgil.SDK.Common; + using Virgil.SDK.Web.Connection; + + /// + /// The class provides operations with Virgil Cards service. + /// + public class CardClient : ICardClient + { + private readonly IConnection connection; + private readonly IJsonSerializer serializer; + + /// + /// Initializes a new instance of the class. + /// This class represents a Virgil Security service client and contains + /// all methods to interaction with server. + /// + public CardClient() : + this(new ServiceConnection + { + BaseURL = new Uri("https://api.virgilsecurity.com") + }) + { + } + + /// + /// Initializes a new instance of the class. + /// + public CardClient(string apiUrl) : + this(new ServiceConnection + { + BaseURL = new Uri(apiUrl) + }) + { + } + + /// + /// Initializes a new instance of the class. + /// + public CardClient(IConnection connection) + { + this.connection = connection; + this.serializer = Configuration.Serializer; + } + + + /// + /// Searches a cards on Virgil Services by specified identity. + /// + /// The identity. + /// The string representation of token. + /// A list of found cards in raw form. + /// + /// + /// var client = new CardsClient(); + /// var rawCards = await client.SearchCardsAsync("Alice", "[YOUR_JWT_TOKEN_HERE]"); + /// + /// + public async Task> SearchCardsAsync(string identity, string token) + { + if (String.IsNullOrWhiteSpace(identity)) + { + throw new ArgumentNullException(nameof(identity)); + } + + if (String.IsNullOrWhiteSpace(token)) + { + throw new ArgumentNullException(nameof(token)); + } + + var request = HttpRequest.Create(HttpRequestMethod.Post) + .WithEndpoint("/card/v5/actions/search") + .WithBody(this.serializer, + new SearchCriteria() { Identity = identity }); + + var response = await this.connection.SendAsync(request, token).ConfigureAwait(false); + + var cards = response + .HandleError(this.serializer) + .Parse(this.serializer) + .ToList(); + + return cards; + } + + /// + /// Gets a card from Virgil Services by specified card ID. + /// + /// The card ID + /// The string representation of token. + /// An instance of class and flag, + /// which determines whether or not this raw card is superseded. + /// + /// + /// var client = new CardsClient(); + /// var (cardRaw, isOutDated) = await client.GetCardAsync("[CARD_ID_HERE]", "[YOUR_JWT_TOKEN_HERE]"); + /// + /// + public async Task> GetCardAsync(string cardId, string token) + { + if (string.IsNullOrWhiteSpace(cardId)) + { + throw new ArgumentNullException(nameof(cardId)); + } + + if (String.IsNullOrWhiteSpace(token)) + { + throw new ArgumentNullException(nameof(token)); + } + + + var request = HttpRequest.Create(HttpRequestMethod.Get) + .WithEndpoint($"/card/v5/{cardId}"); + + var response = await this.connection.SendAsync(request, token) + .ConfigureAwait(false); + + var cardRaw = response + .HandleError(this.serializer) + .Parse(this.serializer); + var supersededHeader = response.Headers.FirstOrDefault(x => x.Key == "X-Virgil-Is-Superseeded"); + var superseded = (supersededHeader.Value != null) && supersededHeader.Value == "true"; + return new Tuple(cardRaw, superseded); + } + + /// + /// Publishes card in Virgil Cards service. + /// + /// An instance of class + /// The string representation of token. + /// published raw card. + /// + /// + /// + /// var crypto = new VirgilCrypto(); + /// var keyPair = crypto.GenerateKeys(); + /// var rawCardContent = new RawCardContent() + /// { + /// CreatedAt = DateTime.UtcNow, + /// Identity = "test", + /// PublicKey = crypto.ExportPublicKey(keyPair.PublicKey), + /// Version = "5.0" + /// }; + /// var model = new RawSignedModel() { ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent) }; + /// + /// var signer = new ModelSigner(new VirgilCardCrypto()); + /// signer.SelfSign(model, keyPair.PrivateKey); + /// + /// var jwtGenerator = new JwtGenerator( + /// "[APP_ID_HERE]", + /// "[API_PRIVATE_KEY_HERE]", + /// "[API_PUBLIC_KEY_ID_HERE]", + /// TimeSpan.FromMinutes(10), + /// new VirgilAccessTokenSigner() + /// ); + /// var token = jwtGenerator.GenerateToken(rawCardContent.Identity); + /// + /// var client = new CardsClient(); + /// await client.PublishCardAsync(model, token.ToString()); + /// + /// + public async Task PublishCardAsync(RawSignedModel request, string token) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (String.IsNullOrWhiteSpace(token)) + { + throw new ArgumentNullException(nameof(token)); + } + + var postRequest = HttpRequest.Create(HttpRequestMethod.Post) + .WithEndpoint("/card/v5") + .WithBody(this.serializer, request); + + var response = await this.connection.SendAsync(postRequest, token).ConfigureAwait(false); + + return response + .HandleError(this.serializer) + .Parse(this.serializer); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/AddRelationRequest.cs b/SDK/Source/Virgil.SDK.Shared/Web/ClientException.cs similarity index 80% rename from SDK/Source/Virgil.SDK.Shared/Client/AddRelationRequest.cs rename to SDK/Source/Virgil.SDK.Shared/Web/ClientException.cs index 31af7c78..45182bef 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/AddRelationRequest.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/ClientException.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,16 +34,18 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Web { - public class AddRelationRequest : SignableRequest + public class ClientException : VirgilException { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// a snapshot model for - public AddRelationRequest(PublishCardSnapshotModel snapshot) : base(snapshot) + public ClientException(int serviceErrorCode, string message) : base(message) { + this.ServiceErrorCode = serviceErrorCode; } + + public readonly int ServiceErrorCode; } } diff --git a/SDK/Source/Virgil.SDK.Shared/Common/JsonSerializer.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpMethodExtensions.cs old mode 100644 new mode 100755 similarity index 71% rename from SDK/Source/Virgil.SDK.Shared/Common/JsonSerializer.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpMethodExtensions.cs index e7a0f761..63e441a4 --- a/SDK/Source/Virgil.SDK.Shared/Common/JsonSerializer.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpMethodExtensions.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,29 +34,24 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Common +namespace Virgil.SDK.Web.Connection { - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - - internal class JsonSerializer + using System; + using System.Net.Http; + + public static class HttpMethodExtensions { - private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings + public static HttpMethod GetMethod(this HttpRequestMethod requestMethod) { - Converters = + switch (requestMethod) { - new StringEnumConverter() + case HttpRequestMethod.Get: return HttpMethod.Get; + case HttpRequestMethod.Post: return HttpMethod.Post; + case HttpRequestMethod.Put: return HttpMethod.Put; + case HttpRequestMethod.Delete: return HttpMethod.Delete; + default: + throw new ArgumentOutOfRangeException(nameof(requestMethod)); } - }; - - public static string Serialize(object model) - { - return JsonConvert.SerializeObject(model, Settings); - } - - public static TModel Deserialize(string json) - { - return JsonConvert.DeserializeObject(json, Settings); } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.NetFx/Device/DeviceManager.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequest.cs old mode 100644 new mode 100755 similarity index 66% rename from SDK/Source/Virgil.SDK.NetFx/Device/DeviceManager.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequest.cs index 13aa07aa..363c4d6f --- a/SDK/Source/Virgil.SDK.NetFx/Device/DeviceManager.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequest.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,46 +34,47 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Device +namespace Virgil.SDK.Web.Connection { - using System; - + using System.Collections.Generic; + /// - /// The provides an information about the device such as assigned name, - /// device model, and operating-system name and version. + /// default implementation"/> /// - public class DeviceManager : IDeviceManager + /// + public class HttpRequest : IRequest { /// - /// Gets the name of the current device. + /// Initializes a new instance of the class. /// - public string GetDeviceName() + public HttpRequest() { - return Environment.MachineName; + this.Headers = new Dictionary(); } /// - /// Gets the name of the operating system running on the device represented by the receiver. + /// Gets the endpoint. Does not include server base address /// - public string GetSystemName() - { - return Enum.GetName(typeof(PlatformID), Environment.OSVersion.Platform); - } + public string Endpoint { get; set; } /// - /// Gets the current version of the operating system. + /// Gets the requests body. /// - public string GetSystemVersion() - { - return Environment.Version.ToString(); - } + public string Body { get; set; } /// - /// Gets the model of the device. + /// Gets the http headers. /// - public string GetDeviceModel() + public IDictionary Headers { get; set; } + + /// + /// Gets the request method. + /// + public HttpRequestMethod Method { get; set; } + + internal static HttpRequest Create(HttpRequestMethod method) { - return "Undefined"; + return new HttpRequest {Method = method}; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/RevokeCardRequest.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestExtensions.cs similarity index 62% rename from SDK/Source/Virgil.SDK.Shared/Client/RevokeCardRequest.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestExtensions.cs index 3b73c5f2..5cc66358 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/RevokeCardRequest.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestExtensions.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,29 +34,38 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Web.Connection { + using Virgil.SDK.Common; + /// - /// Represents an information about revoking card request. + /// Extensions to help construct http requests /// - public class RevokeCardRequest : SignableRequest + public static class HttpRequestExtensions { /// - /// Initializes a new instance of the class. + /// Sets the request enpoint /// - /// The stringified request. - public RevokeCardRequest(string stringifiedRequest) : base(stringifiedRequest) + /// The request. + /// The endpoint. + /// + public static HttpRequest WithEndpoint(this HttpRequest request, string endpoint) { + request.Endpoint = endpoint; + return request; } - + /// - /// Initializes a new instance of the class. + /// Withes the body. /// - /// The card ID to be revoked. - /// The revocation reason. - public RevokeCardRequest(string cardId, RevocationReason reason) - : base(new RevokeCardSnapshotModel { CardId = cardId, Reason = reason }) + /// The request. + /// The serializer. + /// The body. + /// + public static HttpRequest WithBody(this HttpRequest request, IJsonSerializer serializer, object body) { + request.Body = serializer.Serialize(body); + return request; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/CardScope.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestMethod.cs old mode 100644 new mode 100755 similarity index 86% rename from SDK/Source/Virgil.SDK.Shared/Client/CardScope.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestMethod.cs index bd0bca3a..6c8c0893 --- a/SDK/Source/Virgil.SDK.Shared/Client/CardScope.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpRequestMethod.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,16 +34,16 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Web.Connection { - using System.Runtime.Serialization; - - public enum CardScope + /// + /// Represents HTTP request methods + /// + public enum HttpRequestMethod { - [EnumMember(Value = "application")] - Application, - - [EnumMember(Value = "global")] - Global + Get, + Post, + Put, + Delete } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Credentials.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpResponse.cs old mode 100644 new mode 100755 similarity index 77% rename from SDK/Source/Virgil.SDK.Shared/Credentials.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpResponse.cs index d53c3407..690c7da4 --- a/SDK/Source/Virgil.SDK.Shared/Credentials.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/HttpResponse.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,23 +34,28 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK +namespace Virgil.SDK.Web.Connection { - using Virgil.SDK.Cryptography; + using System.Collections.Generic; /// - /// Provides the base authentication class for retrieving credentials for the high-level API. + /// default implementation /// - public abstract class Credentials + public class HttpResponse : IResponse { /// - /// Gets the application used to authenticate Publish/Revoke Card requests. + /// Raw response body. /// - public abstract IPrivateKey GetAppKey(ICrypto crypto); + public string Body { get; set; } /// - /// Gets the application identifier. + /// Information about the API. /// - public abstract string GetAppId(); + public IReadOnlyDictionary Headers { get; set; } + + /// + /// The response status code. + /// + public int StatusCode { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/CardVerifierInfo.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IConnection.cs similarity index 74% rename from SDK/Source/Virgil.SDK.Shared/CardVerifierInfo.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/IConnection.cs index f233f414..87c5de3a 100644 --- a/SDK/Source/Virgil.SDK.Shared/CardVerifierInfo.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IConnection.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,22 +34,26 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK +namespace Virgil.SDK.Web.Connection { + using System; + using System.Threading.Tasks; + /// - /// The class represents an information about Virgil Card - /// verifier such as Public key and Card Id. + /// A connection for making HTTP requests against URI endpoints. /// - public class CardVerifierInfo + public interface IConnection { /// - /// Gets or sets the Virgil Card identifier. + /// Base address for the connection. /// - public string CardId { get; set; } + Uri BaseURL { get; } /// - /// Gets or sets the Public key value. + /// Sends an HTTP request to the API. /// - public VirgilBuffer PublicKeyData { get; set; } + /// The HTTP request details. + /// The access token. + Task SendAsync(IRequest request, string token); } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Client/ISignableRequest.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IRequest.cs similarity index 77% rename from SDK/Source/Virgil.SDK.Shared/Client/ISignableRequest.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/IRequest.cs index ce52a50d..aaa71d4f 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/ISignableRequest.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IRequest.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,28 +34,33 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Client +namespace Virgil.SDK.Web.Connection { using System.Collections.Generic; - + /// - /// Provides a mechanism for building signable requests. + /// Represent a generic HTTP request /// - public interface ISignableRequest + public interface IRequest { /// - /// Gets the list of request signatures. + /// Gets the endpoint. Does not include server base address + /// + string Endpoint { get; } + + /// + /// Gets the request method. /// - IReadOnlyDictionary Signatures { get; } + HttpRequestMethod Method { get; } /// - /// Gets the snapshot value, that has been taken from request model. + /// Gets the http headers. /// - byte[] Snapshot { get; } + IDictionary Headers { get; } /// - /// Appends the signature of request fingerprint. + /// Gets the requests body. /// - void AppendSignature(string cardId, byte[] signature); + string Body { get; } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Cryptography/PrivateKey.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IResponse.cs similarity index 78% rename from SDK/Source/Virgil.SDK.Shared/Cryptography/PrivateKey.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/IResponse.cs index 00adb8bc..ec1da3f1 100644 --- a/SDK/Source/Virgil.SDK.Shared/Cryptography/PrivateKey.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/IResponse.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,22 +34,28 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Cryptography +namespace Virgil.SDK.Web.Connection { + using System.Collections.Generic; + /// - /// The object represents an opaque reference to keying material - /// that is managed by the agent. + /// Represents a generic HTTP response /// - internal class PrivateKey : IPrivateKey + public interface IResponse { /// - /// Gets or sets the public key. + /// Raw response body. /// - internal byte[] ReceiverId { get; set; } + string Body { get; } /// - /// Gets or sets the value. + /// Information about the API. /// - internal byte[] Value { get; set; } + IReadOnlyDictionary Headers { get; } + + /// + /// The response status code. + /// + int StatusCode { get; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Connection/ResponseExtensions.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ResponseExtensions.cs new file mode 100644 index 00000000..da0e7477 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ResponseExtensions.cs @@ -0,0 +1,92 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +namespace Virgil.SDK.Web.Connection +{ + using Virgil.SDK.Common; + + public static class ResponseExtensions + { + public static IResponse HandleError(this IResponse response, IJsonSerializer serializer) + { + string errorMessage; + + switch (response.StatusCode) + { + case 200: // OK + case 201: // Created + case 202: // Accepted + case 203: // Non-Authoritative Information + case 204: // No Content + + // request sent successfully + return response; + + case 400: errorMessage = "Request Error"; break; + case 401: errorMessage = "Authorization Error"; break; + case 404: errorMessage = "Entity Not Found"; break; + case 405: errorMessage = "Method Not Allowed"; break; + case 500: errorMessage = "Internal Server Error"; break; + + default: + errorMessage = $"Undefined Exception (Http Status Code: {response.StatusCode})"; + break; + } + + var errorCode = 0; + if (!string.IsNullOrWhiteSpace(response.Body)){ + var error = serializer.Deserialize(response.Body); + errorCode = error?.ErrorCode ?? 0; + if (error != null && error.Message != null) + { + errorMessage += $": {error.Message}"; + } + } + + if (response.StatusCode == 401) + { + throw new UnauthorizedClientException(errorCode, errorMessage); + } + + throw new ClientException(errorCode, errorMessage); + } + + public static TResult Parse(this IResponse response, IJsonSerializer serializer) + { + return serializer.Deserialize(response.Body); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceConnection.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceConnection.cs new file mode 100644 index 00000000..938ccbdf --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceConnection.cs @@ -0,0 +1,145 @@ +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. +// +// Lead Maintainer: Virgil Security Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// (1) Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// (2) Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// (3) Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System.Net; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Web.Connection +{ + using System; + using System.Linq; + using System.Net.Http; + using System.Text; + using System.Threading.Tasks; + + public class ServiceConnection : IConnection + { + /// + /// The access token header name + /// + protected const string AccessTokenHeaderName = "Authorization"; + + /// + // Base URL for API requests. Defaults to the public Virgil API, but + // can be set to a domain endpoint to use with Virgil Enterprise. + /// + /// + /// BaseURL should always be specified with a trailing slash. + /// + public Uri BaseURL { get; set; } + + /// + /// Gets or sets the Json Web Token. + /// + public IAccessTokenProvider AccessTokenProvider { get; set; } + + /// + /// Sends an HTTP request to the API. + /// + /// The HTTP request details. + /// The access token. + /// Response + public virtual async Task SendAsync(IRequest request, string token) + { + using (var httpClient = new HttpClient()) + { + var nativeRequest = this.GetNativeRequest(request, token); + var nativeResponse = await httpClient.SendAsync(nativeRequest).ConfigureAwait(false); + + var content = nativeResponse.Content.ReadAsStringAsync().Result; + var response = new HttpResponse + { + Body = content, + Headers = nativeResponse.Headers.ToDictionary(it => it.Key, it => it.Value.FirstOrDefault()), + StatusCode = (int)nativeResponse.StatusCode + }; + + return response; + } + } + /* + private async Task TryRefreshAccessTokenAndSendAgain(IRequest request) + { + var httpClient = new HttpClient(); + var nativeResponse = new HttpResponseMessage(); + + for (int attempt = 0; attempt < 3; attempt++) + { + var nativeRequest = await this.GetNativeRequestAsync(request); + nativeResponse = await httpClient.SendAsync(nativeRequest).ConfigureAwait(false); + if (nativeResponse.StatusCode != HttpStatusCode.Unauthorized) + { + break; + } + } + return nativeResponse; + }*/ + + /// + /// Produces native HTTP request. + /// + /// The request. + /// The access token. + /// HttpRequestMessage + protected virtual HttpRequestMessage GetNativeRequest(IRequest request, string token) + { + var message = new HttpRequestMessage(request.Method.GetMethod(), + new Uri(this.BaseURL, request.Endpoint)); + + /* + if (nativeResponse.StatusCode == HttpStatusCode.Unauthorized) + { + nativeResponse = await TryRefreshAccessTokenAndSendAgain(request); + } + */ + if (request.Headers != null) + { + message.Headers.TryAddWithoutValidation(AccessTokenHeaderName, $"Virgil {token}"); + + foreach (var header in request.Headers) + { + message.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + } + + if (request.Method != HttpRequestMethod.Get) + { + message.Content = new StringContent(request.Body, Encoding.UTF8, "application/json"); + } + return message; + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Common/IRequestSigner.cs b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceError.cs similarity index 82% rename from SDK/Source/Virgil.SDK.Shared/Common/IRequestSigner.cs rename to SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceError.cs index 1450f5fb..a857869b 100644 --- a/SDK/Source/Virgil.SDK.Shared/Common/IRequestSigner.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/Connection/ServiceError.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,14 +34,17 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Common +namespace Virgil.SDK.Web.Connection { - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - - public interface IRequestSigner + using System.Runtime.Serialization; + + [DataContract] + public class ServiceError { - void AuthoritySign(ISignableRequest request, string appId, IPrivateKey appKey); - void SelfSign(ISignableRequest request, IPrivateKey privateKey); + [DataMember(Name = "code")] + public int ErrorCode { get; set; } + + [DataMember(Name = "message")] + public string Message { get; set; } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/ICardClient.cs b/SDK/Source/Virgil.SDK.Shared/Web/ICardClient.cs new file mode 100644 index 00000000..f48bd138 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/ICardClient.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Web +{ + /// + /// The interface defines a list of operations with Virgil Cards service. + /// + public interface ICardClient + { + /// + /// Searches a cards on Virgil Services by specified identity. + /// + /// The identity. + /// The string representation of token. + /// A list of found cards in raw form. + Task> SearchCardsAsync(string identity, string token); + + /// + /// Gets a card from Virgil Services by specified card ID. + /// + /// The card ID + /// The string representation of token. + /// An instance of class and flag, + /// which determines whether or not this raw card is superseded. + Task> GetCardAsync(string cardId, string token); + + /// + /// Publishes card in Virgil Cards service. + /// + /// An instance of class + /// The string representation of token. + /// published raw card. + Task PublishCardAsync(RawSignedModel request, string token); + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Client/CardMetaModel.cs b/SDK/Source/Virgil.SDK.Shared/Web/RawCardContent.cs similarity index 63% rename from SDK/Source/Virgil.SDK.Shared/Client/CardMetaModel.cs rename to SDK/Source/Virgil.SDK.Shared/Web/RawCardContent.cs index 8e112509..fbeb9178 100644 --- a/SDK/Source/Virgil.SDK.Shared/Client/CardMetaModel.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/RawCardContent.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -33,29 +33,45 @@ // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #endregion - -namespace Virgil.SDK.Client +namespace Virgil.SDK.Web { using System; - using System.Collections.Generic; - - using Newtonsoft.Json; + using System.Runtime.Serialization; /// - /// The represents an meta information about a Card. + /// provides content of Virgil Card. /// - public class CardMetaModel + [DataContract] + public class RawCardContent { - [JsonProperty("signs")] - public Dictionary Signatures { get; set; } + /// + /// Card identity. + /// + [DataMember(Name = "identity")] + public string Identity { get; set; } - [JsonProperty("relations")] - public Dictionary Relations { get; set; } + /// + /// Public key data. + /// + [DataMember(Name = "public_key")] + public byte[] PublicKey { get; set; } - [JsonProperty("created_at")] + /// + /// Card version. + /// + [DataMember(Name = "version")] + public string Version { get; set; } + + /// + /// UTC creation date. + /// + [DataMember(Name = "created_at")] public DateTime CreatedAt { get; set; } - [JsonProperty("card_version")] - public string Version { get; set; } + /// + /// Id of outdated previous Virgil Card with same identity which was superseded by current card. + /// + [DataMember (EmitDefaultValue = false, Name = "previous_card_id")] + public string PreviousCardId { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Contracts/Cryptography/KeyPair.cs b/SDK/Source/Virgil.SDK.Shared/Web/RawSignature.cs similarity index 65% rename from SDK/Source/Virgil.SDK.Contracts/Cryptography/KeyPair.cs rename to SDK/Source/Virgil.SDK.Shared/Web/RawSignature.cs index 14a630e0..273e70c3 100644 --- a/SDK/Source/Virgil.SDK.Contracts/Cryptography/KeyPair.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/RawSignature.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2016 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,31 +34,37 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Cryptography +namespace Virgil.SDK.Web { + using System.Runtime.Serialization; + /// - /// The class represents an asymmetric key pair that is - /// comprised of both public and private keys. + /// provides signature for . /// - public class KeyPair + [DataContract] + public class RawSignature { /// - /// Initializes a new instance of the class. + /// Signer id. It must be unique among the signatures. /// - public KeyPair(IPublicKey publicKey, IPrivateKey privateKey) - { - this.PublicKey = publicKey; - this.PrivateKey = privateKey; - } + /// + /// Reserved values: + /// Self signatures: "self" + /// Virgil Service signatures: "virgil" + /// + [DataMember(Name = "signer", EmitDefaultValue = false)] + public string Signer { get; set; } /// - /// Gets the public key. + /// Signature data. /// - public IPublicKey PublicKey { get; } + [DataMember(Name = "signature", EmitDefaultValue = false)] + public byte[] Signature { get; set; } /// - /// Gets the private key. + /// Additional data. /// - public IPrivateKey PrivateKey { get; } + [DataMember(Name = "snapshot", EmitDefaultValue = false)] + public byte[] Snapshot { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/IdentityConfirmation.cs b/SDK/Source/Virgil.SDK.Shared/Web/RawSignedModel.cs similarity index 65% rename from SDK/Source/Virgil.SDK.Shared/IdentityConfirmation.cs rename to SDK/Source/Virgil.SDK.Shared/Web/RawSignedModel.cs index 142a44e6..eaa47518 100644 --- a/SDK/Source/Virgil.SDK.Shared/IdentityConfirmation.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/RawSignedModel.cs @@ -1,5 +1,5 @@ -#region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +#region Copyright (C) Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,32 +34,36 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK -{ - using System.Threading.Tasks; +using Virgil.SDK.Common; - using Virgil.SDK.Client; +namespace Virgil.SDK.Web +{ + using System.Collections.Generic; + using System.Runtime.Serialization; /// - /// The class is a base class for all identity confirmation types. + /// The provides transitional model of + /// and used by . /// - public abstract class IdentityConfirmation + [DataContract] + public class RawSignedModel { /// - /// Initializes a new instance of the class. + /// Snapshot of . /// - protected IdentityConfirmation() - { - } + /// How to get snapshot of object . + [DataMember(Name = "content_snapshot")] + public byte[] ContentSnapshot { get; internal set; } /// - /// Confirms the identity verificatio and grabs a validation token. + /// A list of signatures. /// - /// The attempt. - /// The Virgil API client. - /// - /// A string that represents identity validation token. - /// - internal abstract Task ConfirmAndGrabValidationTokenAsync(IdentityVerificationAttempt attempt, VirgilClient client); + [DataMember(Name = "signatures", EmitDefaultValue = false)] + public IList Signatures { get; internal set; } + + internal RawSignedModel() + { + Signatures = new List(); + } } -} \ No newline at end of file +} diff --git a/SDK/Source/Virgil.SDK.Shared/Web/RawSignedModelExtensions.cs b/SDK/Source/Virgil.SDK.Shared/Web/RawSignedModelExtensions.cs new file mode 100644 index 00000000..d55904f8 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/RawSignedModelExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Web +{ + public static class RawSignedModelExtensions + { + /// + /// Exports a RawSignedModel into string. Use this method to transmit the card + /// signing request through the network. + /// + public static string ExportAsString(this RawSignedModel model) + { + var rawCardBytes = Bytes.FromString(model.ExportAsJson()); + var rawCardString = Bytes.ToString(rawCardBytes, StringEncoding.BASE64); + return rawCardString; + } + + /// + /// Exports a RawSignedModel into json. Use this method to transmit the card + /// signing request through the network. + /// + public static string ExportAsJson(this RawSignedModel model) + { + return Configuration.Serializer.Serialize(model); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilApiException.cs b/SDK/Source/Virgil.SDK.Shared/Web/SearchCriteria.cs similarity index 79% rename from SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilApiException.cs rename to SDK/Source/Virgil.SDK.Shared/Web/SearchCriteria.cs index 54588ec1..bc7208a1 100644 --- a/SDK/Source/Virgil.SDK.Shared/Exceptions/VirgilApiException.cs +++ b/SDK/Source/Virgil.SDK.Shared/Web/SearchCriteria.cs @@ -1,5 +1,5 @@ #region Copyright (C) Virgil Security Inc. -// Copyright (C) 2015-2017 Virgil Security Inc. +// Copyright (C) 2015-2018 Virgil Security Inc. // // Lead Maintainer: Virgil Security Inc. // @@ -34,19 +34,21 @@ // POSSIBILITY OF SUCH DAMAGE. #endregion -namespace Virgil.SDK.Exceptions -{ +namespace Virgil.SDK.Web +{ + using System.Collections.Generic; + using System.Runtime.Serialization; + /// - /// Represents an error during interaction with Virgil high-level API. + /// The search criteria that determines what cards list to retrieve. /// - public class VirgilApiException : VirgilException + [DataContract] + public class SearchCriteria { /// - /// Initializes a new instance of the class. + /// Gets or sets the identities. /// - /// The message. - public VirgilApiException(string message) : base(message) - { - } + [DataMember(Name = "identity")] + public string Identity { get; set; } } } \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Shared/Web/UnauthorizedClientException.cs b/SDK/Source/Virgil.SDK.Shared/Web/UnauthorizedClientException.cs new file mode 100644 index 00000000..8c31fb42 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Shared/Web/UnauthorizedClientException.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Virgil.SDK.Web +{ + public class UnauthorizedClientException : ClientException + { + /// + /// Initializes a new instance of the class. + /// + public UnauthorizedClientException(int serviceErrorCode, string message) : base(serviceErrorCode, message) + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/AppSettings.cs b/SDK/Source/Virgil.SDK.Tests.Droid/AppSettings.cs new file mode 100644 index 00000000..ec6de9ea --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/AppSettings.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using PCLAppConfig; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests +{ + public class AppSettings + { + static AppSettings(){ + } + + public static string AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + public static string AccounId = ConfigurationManager.AppSettings["virgil:AccountID"]; + public static string AppPrivateKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; + public static string ApiPublicKeyId = ConfigurationManager.AppSettings["virgil:AccessPublicKeyId"]; + public static string ApiPrivateKeyBase64 = ConfigurationManager.AppSettings["virgil:AccessPrivateKeyBase64"]; + public static string ServiceCardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"]; + public static string ServicePublicKeyPemBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyPemBase64"]; + public static string ServicePublicKeyDerBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"]; + public static string CryptoCompatibilityData = ""; + public static string OutputTestDataPath = ConfigurationManager.AppSettings["test:OutputDataPath"]; + public static string CardsServiceAddress = ConfigurationManager.AppSettings["virgil:CardsServicesAddressV5"]; + + public static string PrivateKeySTC31_1 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_1"]; + public static string PrivateKeySTC31_2 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_2"]; + public static string PublicKeySTC32 = ConfigurationManager.AppSettings["test:PublicKeySTC32"]; + + public static string ImportedAccessPublicKeyId = ConfigurationManager.AppSettings["test:ImportedAccessPublicKeyId"]; + public static string ImportedAccessPublicKey = ConfigurationManager.AppSettings["test:ImportedAccessPublicKey"]; + + public static string PredefinedPrivateKeyBase64 = ConfigurationManager.AppSettings["test:PredefinedPrivateKeyBase64"]; + + public static string ImportedJwt = ConfigurationManager.AppSettings["test:ImportedJwt"]; + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Assets/AboutAssets.txt b/SDK/Source/Virgil.SDK.Tests.Droid/Assets/AboutAssets.txt new file mode 100644 index 00000000..a9b0638e --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with your package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Assets/crypto_compatibility_data.json b/SDK/Source/Virgil.SDK.Tests.Droid/Assets/crypto_compatibility_data.json new file mode 100644 index 00000000..d3d9385f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Assets/crypto_compatibility_data.json @@ -0,0 +1,54 @@ +{ + "encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIFx8vNiUAME3rwAoVMyuZg/F14FcMF5WETOeEV3Zr8c7", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIBYgIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQg9b1JYQ61xgfxYN1lFZkPOlB7XDMd/rxcVk8r2MPGntMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB066Ul4v6X9zUXoHx8TxlgaQC8c6ayVchkItZDfRZGwTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMGtLjjW6Rl3JMCh5683PT5E1LDdaspCLUnBJjWarkRnbcrmMt8yqLle6H4QVeqvIhjBRMB0GCWCGSAFlAwQBKgQQrP3B71mD165GE5vhEomT7QQwy25y+b+4DEHPp1RLHatp7uJ4ZwXMrsawrj/TOlCmz0oGz91v19McaA+r1wIMCnukMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDDGYn3cJsIhBAHq4F4sC+6JJBMT3Jh3GcrDp/F7E0LPRVHEXf9GzfvlW3SOzfG56CsLOmjIdZoqQgne8VLHWUYMXQKDae3s3AQBuo7d7EytYtUAgdw==" + }, + "encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIKyyfp+ssJL6AkwndBWL6jOPgswH+BVDzxU8md6nA40t", + "MC4CAQAwBQYDK2VwBCIEIAFYY8PG8enCO6NdUv1UVnC65ryr2mrGV6QDlJEliv3y", + "MC4CAQAwBQYDK2VwBCIEIATkmvo7jh0syRtTg1mNfSJNvqB1V9/bEKijP+rmK5MO", + "MC4CAQAwBQYDK2VwBCIEIK7KLGRPADz3NKk4p0hq3q/wwqN5g08pzN0b9+0NbgXq", + "MC4CAQAwBQYDK2VwBCIEIOJIlOdeAygksA2Y4RHJBQ51emPtVW257jeWiwMnS3nQ", + "MC4CAQAwBQYDK2VwBCIEIPVooGKp/JArB4dD5LDDjHeIsbBkAfDfWNgzFoAYov1C", + "MC4CAQAwBQYDK2VwBCIEIFEaV3yA+7ui8SgHLVzjCY/ZLfc5m8FMHe6nzlV/fOk3", + "MC4CAQAwBQYDK2VwBCIEIHLc4yhkFXMceatKElNvmgIsixBc0KkRxEL/FmnhzJTx" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIJEQIBADCCCQoGCSqGSIb3DQEHA6CCCPswggj3AgECMYIIyDCCARUCAQKgIgQgAz7ucGlal9Ci/bo+cUwEjgCssJyXvV4BhxM3y6oKuk0wBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCSZsPUeZvdKO5SoLVXnujHqj2L3RnbtWCV8jd3J/Dq7DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMAYsEjCm0IZfJ2Zmv7Hqp+CAEm6XaHjcvEMx0usIlSMtS+Nv5ZFuJBbsrx7kGbncOTBRMB0GCWCGSAFlAwQBKgQQVbZvllp7v53v+5zQE1RdVwQwd4dIDBJWocDNkETlUeIvQ7dE3k/0KNsFg5QUXIWZ49/pfDDHZ4cyaBAxm4pTVDUgMIIBFQIBAqAiBCAKaQVVewI74Q1xvI3qFj99IInXXHQpYwvCJGaHM2a3WTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAJTbV4mwvvX9QMIp7ZeI4vULr20xFVvIidWm5f8VLLRrMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZwA6LAIeLvksS/kjjsf5u0ON6KOkE3Na+Gr1YUN7D89SlGxoPM3AGS5Np8IhVXvNMFEwHQYJYIZIAWUDBAEqBBCxoYn5gb9l0DT8bXU/g9CZBDCID58W78ALWYdwoNtINpRxKNxdo7cic16XEG6z9KWWs8mEumowndsNL2dZPFvLpLcwggEVAgECoCIEIAuNcSL1B0U0778/hDjLqPkwtE8jO9YcZfhIgMXHa+msMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXpjJEOd7Ay5Bk+sCHZxL0LqjG2WGL7XiDXYb5nonPcUwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDvNhxjgDfrUdd04KW24RsXYc1nqFidBUxw7p9ItEt7plwkNTs2bzkMpHe7ufTQc3AwUTAdBglghkgBZQMEASoEEJHRiqJIuGuewZQVOv9rqCwEMIdasg5OxHuw1PHDd4bMqL0V3+FmSzxevYVDHYu9+M6KDmdDsYD2TbTnze6qQ2MyKTCCARUCAQKgIgQgF7uvNtMIAur6T5hUk8YmA+wS5l4nA/r1lsdhE94H29MwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB5dQD12I+x/u+A6nbvHSKS8BN5HURHBrCI+GjAyTqXHTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMEZuhCp3UsxPAkB58kKEvD9cAKIbOSG3Y/B8gCQn6VStsUqd+hlgT8xuJe9ZlXIzpTBRMB0GCWCGSAFlAwQBKgQQtcAXjSkyM/p6ai/dHH1ITAQwitM226Beplv6WD4WJb0IJS+4tu1DQ0Yc9jMoPH2Bv9GlElD6Ru3Yt6uwFIeI9IcDMIIBFQIBAqAiBCAnDrtwjOuscTQEPxvwxEZMMNw4hlDChj4KrIE9vjm8+jAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMbosYfz7z/c88WONdyQ3WBBZHDhGTM9lQ+NaAGNm0ZFMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQw+z/kd8iFoSsJ6oodl647M+uAZMUHtpbAskFLSlVybwIcO8Yukg1z1zi/wmohbI5JMFEwHQYJYIZIAWUDBAEqBBAT6xH+f9z8B40iX3V+FG3XBDBcKWor27gd3tPfwMrx+K55I6fDMVQuh96IWTvqxpiIDkHQNWcraI8iijGbKYOm4WcwggEVAgECoCIEIGSLvD61SgkWz7l3Zw9/N4rIBkR6n9Qo7Cs21gCn7AVjMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAGC9LfF1yG5JrBwGLFq1qJlcRl+ChOFG7jyTN4PXfiTwwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDD6IHUf8BozheyYWRW9VlZiIUjVUL/6sj9rRx0qV6CZ5hgHs5IZhKRDSkY1fsia6xIwUTAdBglghkgBZQMEASoEEAR8+jPqogiQWEjgoQ5qp/8EMMQgyW7+Lpj9sVsXpw7hPKtJMcR7ycqGDibmQCUR5kv+I2qoB4CFcKepeUcyXweiPDCCARUCAQKgIgQg7K3yFDemud3MKRJJxWpd2bSWm7rWjwjv7nmfvOlP+xwwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBOY0OO75qvwmMGABvaF8OD4EvKO0Luq9HnwrlcDBYl0DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMCoDfRigXpu4jgqQJw5mq5SID+d6ey7bfGE27DQgpM++20wH0FVOk+pn5pEm3DKMkjBRMB0GCWCGSAFlAwQBKgQQ4ekdMtGF5pjpdrE/dqEZQAQwyg5JVAgoJYz4mokP5pxxpCZjxR1uHGby9stjwmdg7u8f10xhNMLrnwAQGBNCyBB2MIIBFQIBAqAiBCDx4+HMoUWy/zMQnEfOmK1IrftOktlCECCknqfJgIniyjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC/4OYAGOvfglstuwvmzMH0P897oW00UOJh8z9Oa4drkMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwuguHh66/rA23c1xW+Wrpjs0ZEBUiBxrrRvJeS/S1bKMDDwUHVK/Md9johoDMsbb7MFEwHQYJYIZIAWUDBAEqBBDvsCvGh4Md3BJrkbhjzwy7BDAbVyByTf2TeFeEqDywIfY/dQbQcMtmTD+2Bn/Y0HT1Z7ClAjrcKuxkB9W0Ys1L3FgwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMIe1v++T1huQVtzypcIEf22hv+SZqDTkIAjBWFv3ZouzgqZg9jHLYv6nA1IruM6OegDuBG4s/mm/PQ1bV8brJEZx5BwTuC/b03RhDs3j6LphSJ+8o" + }, + "sign_then_encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBjaHn6Z1QrXdAfRb034JoDhoXM+8hKYiQzQAg6+l419", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIICFQIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB0YhufvezF6W/834kAB7o5LPquTik/0qkMLRlmP7fEGjAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMID/2OZvTt0cClysYG6ZVlKfmEGEJLl12gLZ07qRo3qtm4ARwRoweHtedbzpdRefXjBRMB0GCWCGSAFlAwQBKgQQVdMd5xQjd2DE16rGrBTqIwQw4YxHOLiK8mvvH8cMIPsU0rpsM0fe+ohMnHCaW5ccTdgSMCOyVjaDUMqpl+KvIF4GMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDCZnr2AeX892Duem8KCBsDGBrTA7DBVWSVJHSUwtREFUQS1TSUdORVItSUSiIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwbgwVVklSR0lMLURBVEEtU0lHTkFUVVJFolUEUzBRMA0GCWCGSAFlAwQCAwUABEC9GjnFrMcTJ7YKj46bDyQQ/EEUzuePFOSPk8RKjrFDFCLfLkYH9gVdUCjGrVv07/FcuKEd9ZS86G4tUuh3F9gC7EEbYUtjCnPL31rWnAKeqi04gUq1wFLA1YdtOvAqjZUc1N3LQ+oiTo1ErCJKhRhugpApO2V3YLl/tsU3NbrqQv1rPwjA12G8" + }, + "sign_then_encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIAvWl/kgTqbXQ+cTytIUCZkfjOYv7W6g5eyawFabxScJ", + "MC4CAQAwBQYDK2VwBCIEICGXlHJDS+I7rrqawhJQOJ8XjgOCNasUQcWR6os5wYE4", + "MC4CAQAwBQYDK2VwBCIEIG0S2QFR6u0AOoj8jZhZSObL8NaguY/nVZYs1FVgDpI/", + "MC4CAQAwBQYDK2VwBCIEIGhP0N16y7vcZXNRnhkUyIXNIj90+Swg+w0LRzdDaCsd", + "MC4CAQAwBQYDK2VwBCIEINk1nCOxREjzxD06eprK790GoqNWtWuVAu0fOue9B6Pn" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgZ/5EW3CwoNqvth/AhFM99EUelekEMlGi6b58yOzdzUIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQAiNmc2Y/3No9n6K5HpV0Yj2kIJht68/Qxz2BPTZFcvkTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMIZcBiKH2K5DjF7SRqOELqNPZp4GD0jY4/LoP+1kVSUNWJFNogeUdpsclpktDlcYozBRMB0GCWCGSAFlAwQBKgQQNIzOge5YjNvC95QG3W2oZQQwaxnJRb7j0n5+Doqd4VwbjXHxnYuOpWLDORxdhQjtaWrf8zqcW57ejT5w9GubDjxOMIIBFQIBAqAiBCBsXBt9/JYionc7FscmmxLkYqzQBlugvte3tBgR9+eyADAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMDxkSWypMtiqVQ3avChkE9BP30ta0zctoS4WW0OKRDiMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwBmKs+uwujxGmZcBXVIMv8x2EwJLHkgybdFCrymxAkdcocbAUAR42b0CiecrTBtBqMFEwHQYJYIZIAWUDBAEqBBBnvbvZQTSrb1PaIPmJFox0BDAg9dLzHnUw/QV5lCSVv+tj7wx3ML0ZdXCN14Aielstx7wO2Ygg9ejJ6lzkSJNgJ9EwggEVAgECoCIEIG08tVe/WHb7d+FAaErZRgWQ6M18TWtx0/O1FWmUoKwFMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAMMR5Lljq+Y2g2cespAzlC23CvRJLFaHDsJJBPyWodeswGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDIp0Rh1wwAYb73+t3oiNAT09GspVhS78fwElGFnTtmHzxSER/ugaixuEgzmkD5SdowUTAdBglghkgBZQMEASoEEM5LxKaK2b1dXyt8JXMaWaAEMMmMXWBr3QEB6YaaWwQMpGUQz7M3ri7WPPHtdpFMY1R9wt1quWU2eeFna7n7tKj3mTCCARUCAQKgIgQgpmRIy7nlVoGTkJBOHqEjKdeEcnJu5ahqfjYWrg+Z8oIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBilNAblc9gZ3yzTZHrUaYCdn64Perqaf4YmZXn+/QYGzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMJq9vHZAV4zu0cH5aMvCzBw6HqfiX0kzs4DI2WWPMmExTHfxlqbqB32+kS36HqH/cTBRMB0GCWCGSAFlAwQBKgQQMKacxhPe+eXxZ+sUXSI8/wQwbolTTcvEYTewC7Tyz29pd+FYnT92VdCM1ciI94PywbqZUUCbi32aR0AG1t5geUswMIIBFQIBAqAiBCDC0TMYmYbdpCd0fO+UBsN8Oyix6Q7NNXzVxpua0kGAwTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAEtgpOVQm18owVuPctwdXbQ8iRv24HPf8i64fCbkB0i0MBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZZ7cnK2Sq/KsP54qcN/su+ZEdtJIMunexuXzM2/GtW3yFDm13EPARvEwLiD/qZUOMFEwHQYJYIZIAWUDBAEqBBDphHjyT3NaJV/Rq+r/x4cvBDDtY+WdlzXUsfEQvGp2fBwM8xI6sZRbk68gUuZpCjFICeVsD8pdiS4RrjjnPMY2h1MwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMtbmAUdn9qCGdQPOhoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCBn/kRbcLCg2q+2H8CEUz30RR6V6QQyUaLpvnzI7N3NQjBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQKaB09lKLNo5mLRLxl4S5nI0dbYxwGUYUzXXtdLXnWMf4fxCPR0USW1qyIQLVUeJmtIhET3R/VPhqRrPKsFzyQAB/jziUKj409ykG++1OQg2FE5XhMhQoiFhTf8Cxo2tDeOOXCeQCy1SiG5wYJVXkVXFFNN8b59rJEp8RTRnIR8OfV6MkJsZCS4=" + }, + "generate_signature": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBueB+DRjfF52AK7qTkUUhOEOJwNpzxkt3d00riD7QuI", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "signature": "MFEwDQYJYIZIAWUDBAIDBQAEQAp6LhuwBbtq2UILTQpvlBy+0rPgB9bNP45rU03arAogObdXGRD9bzEob7LzQNE8BWNF/JQY+pL0pC5Z3qH6tAc=" + }, + "sign_then_encrypt_multiple_signers": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIG6wyMA56aGMaKf8kaDqo7j/5onSM3SN6Do5q3P28Xzp", + "public_keys": [ + "MCowBQYDK2VwAyEALSCsIR2pEK5SWR8k1kOqCjkLM7SEoMS98vO4TJ6GMC4=", + "MCowBQYDK2VwAyEA2AsShcg1ZpK5PdUsDpcRKXjs1BMcNb6jHxZ5cD0jYC8=", + "MCowBQYDK2VwAyEA2EOIbFIMSDdd5PebefEH5bAdGqeyFWaBDyKntr8SG2k=", + "MCowBQYDK2VwAyEAZoH5Fn31VuT7xClvY3cLoNMkSQqeR8fPxAEUERFYdSQ=", + "MCowBQYDK2VwAyEAVBmCMI5YvsyCDQv5gyZhm+uWyHTnhILe/K9CNKUqkLw=" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgV+lgOdbbR8aHUjIEx/YblRLUe/bGcH48E86p0I45JkMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCAIRQh5ho70Jl3wuIpZxMv7bRzWgZDoBFtZafbiXCp2jAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMNPkFuMoCS/A9nzgZQ5lie5laQnGcfPYZVm6iwxual6USPOF6oqZd0EJu2xKx188IzBRMB0GCWCGSAFlAwQBKgQQd1cWGby4gwQgB8MTRmQxwgQweMtdoScv4IEQu0jwTXgasA3LvgUOiIAeSvUSdiYlh55Vx6sTe7cXjoheLKclSWgLMIIBFQIBAqAiBCB06AofjB8oEBQU0dRxXdJsbOSUq7Xscawaz29Akghv+DAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC8xBHqoj3SJ3lnrZRi4sKrLpAEv53VuyFeyyZr5parBMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwd/+fkUJ92w1AxbBGEtOZUQXVKplYlbfgZVxTdwPFEFaVxHkRf2DFLjYcA8eJxl+mMFEwHQYJYIZIAWUDBAEqBBB2sx1N39H6gkHGSSDxSWM+BDDQXM5d9avTHrLEzOOwWe3vtpFxkefz0/8T06c3UMxvhMp/TM3xYXgSQ1dDrDuMAVowggEVAgECoCIEIK8P8zsSxEpPs/6UDFfKP3/pz/Gas6c1VMnv7xUOhQVbMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXjeOtEDF+FzRvyGoKlUwfuC+cbGonXmQ1lfbvClLHYMwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDBSEicWwBP9gcdwbi3TlsX3YMWs3ue18iUUltu05uFruh+c2xYwTwo2Zt+oPNHT+mYwUTAdBglghkgBZQMEASoEEJaLW/UPxiYD1z4RQh0qMxMEMKVsy7VquNAYLvuaFdYJszzz5HtqlC9OnCiEOc9gecKL8KQ3bU0l4vL4pFl7SgBCJzCCARUCAQKgIgQgz3bkz4SRK/ndLceAz5A1rc4QpUdQsOKSg8Lpg9Yd29swBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCjOgxFr+VCWdngH0SQMu6bfcUFqWooDGDut0G0t7RSEzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMKADb3wAPzdJ+BsuKBB59pdL3HpV/hCRGtZtzHqfiIdTFsv+kMczigySgKGvysJrKzBRMB0GCWCGSAFlAwQBKgQQ/uq+33Aivg92/9lpF8feHQQwILYYaJz55qTzFwLe21a+oo9av0A/7mNBkqW4ogGn4/fOJ4T2Pwlt8kZor033rBHkMIIBFQIBAqAiBCDX7SnuiYY1nMfPaqFGbEssf4GXA3LlB97QLjJ+CjlazjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAHnBZCXOZ365uuylYUJcsG91xVq46zmnAKkDRI3uOAATMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwM/lDhsv7B0Qq45Zi9pP7oKrlhzhtYlNk8Wh1uKA9mBWLqVQ61NlQVm9F2gk1gpPsMFEwHQYJYIZIAWUDBAEqBBDBBGvJ5lNVVw9/2/JU9ZHSBDA8y9XblGHB40qIniw+TeAt87peZP/mCYd4NCk91wt3perCNMhEJhoBq3KnB91Lyq4wJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMXnmCLfBKuPnH+nxmoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCDPduTPhJEr+d0tx4DPkDWtzhClR1Cw4pKDwumD1h3b2zBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQMbcL2CbQYHafMsmut9uyZ1c4cJGWk2cQZDZ8xcb/4EXeo/cJxFDhc59TVtjIImy8L4xpVLuI6+wGfwGIPmZKwlJubsUEUn+KHvHlS4z41YCsDrxXaDN8luv5jj+ERJg9MVrHttjMTOX0IIVoxcylbi6V2wd7/+KiL0JKx3dV5syJ4by+Y0y6eY=" + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs b/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs new file mode 100644 index 00000000..51a8c6d4 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs @@ -0,0 +1,49 @@ +using System.IO; +using System.Reflection; +using Android.App; +using Android.Content.PM; +using Android.Content.Res; +using Android.OS; +using NUnit.Runner; +using NUnit.Runner.Services; +using PCLAppConfig; +using Virgil.SDK.Tests; + +namespace AndroidUnitTestApp +{ + [Activity(Label = "NUnit 3", MainLauncher = true, Theme = "@android:style/Theme.Holo.Light", + ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity + { + protected override void OnCreate(Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); + + global::Xamarin.Forms.Forms.Init(this, savedInstanceState); + + + ConfigurationManager.Initialise(PCLAppConfig.FileSystemStream.PortableStream.Current); + var AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + // var AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + using (StreamReader sr = new StreamReader(Application.Assets.Open("crypto_compatibility_data.json"))) + { + var content = sr.ReadToEnd(); + AppSettings.CryptoCompatibilityData = content; + } + + // This will load all tests within the current project + var nunit = new NUnit.Runner.App(); + + // If you want to add tests in another assembly + //nunit.AddTestAssembly(typeof(MyTests).Assembly); + + // Do you want to automatically run tests when the app starts? + nunit.Options = new TestOptions + { + AutoRun = true + }; + + LoadApplication(nunit); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs.txt b/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs.txt new file mode 100644 index 00000000..1157296d --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/MainActivity.cs.txt @@ -0,0 +1,67 @@ +// *********************************************************************** +// Copyright (c) 2015 Charlie Poole +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// *********************************************************************** + +using Android.App; +using Android.Content.PM; +using Android.OS; + +namespace Virgil.SDK.Tests.Droid +{ + [Activity(Label = "NUnit 3", MainLauncher = true, Theme= "@android:style/Theme.Holo.Light", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity + { + protected override void OnCreate(Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); + + global::Xamarin.Forms.Forms.Init(this, savedInstanceState); + + // This will load all tests within the current project + var nunit = new NUnit.Runner.App(); + + // If you want to add tests in another assembly + //nunit.AddTestAssembly(typeof(MyTests).Assembly); + + // Available options for testing + nunit.Options = new TestOptions + { + // If True, the tests will run automatically when the app starts + // otherwise you must run them manually. + AutoRun = true, + + // If True, the application will terminate automatically after running the tests. + //TerminateAfterExecution = true, + + // Information about the tcp listener host and port. + // For now, send result as XML to the listening server. + // TcpWriterParameters = new TcpWriterInfo("192.168.0.108", 13000), + + // Creates a NUnit Xml result file on the host file system using PCLStorage library. + CreateXmlResultFile = false + }; + + LoadApplication(nunit); + } + } +} + diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AndroidManifest.xml b/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AndroidManifest.xml new file mode 100644 index 00000000..f6a982f5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..64b40b78 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using Android.App; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("AndroidUnitTestApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.0")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/AboutResources.txt b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/AboutResources.txt new file mode 100644 index 00000000..10f52d46 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/Resource.designer.cs b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/Resource.designer.cs new file mode 100644 index 00000000..a4f7918b --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/Resource.designer.cs @@ -0,0 +1,90 @@ +#pragma warning disable 1591 +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +[assembly: global::Android.Runtime.ResourceDesignerAttribute("Virgil.SDK.Tests.Droid.Resource", IsApplication=true)] + +namespace Virgil.SDK.Tests.Droid +{ + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] + public partial class Resource + { + + static Resource() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + public static void UpdateIdValues() + { + global::Nunit.Runner.Resource.String.ApplicationName = global::Virgil.SDK.Tests.Droid.Resource.String.ApplicationName; + global::Nunit.Runner.Resource.String.Hello = global::Virgil.SDK.Tests.Droid.Resource.String.Hello; + global::PCLAppConfig.FileSystemStream.Resource.String.ApplicationName = global::Virgil.SDK.Tests.Droid.Resource.String.ApplicationName; + global::PCLAppConfig.FileSystemStream.Resource.String.Hello = global::Virgil.SDK.Tests.Droid.Resource.String.Hello; + global::PCLStorage.Resource.String.ApplicationName = global::Virgil.SDK.Tests.Droid.Resource.String.ApplicationName; + global::PCLStorage.Resource.String.Hello = global::Virgil.SDK.Tests.Droid.Resource.String.Hello; + global::Virgil.SDK.Resource.String.ApplicationName = global::Virgil.SDK.Tests.Droid.Resource.String.ApplicationName; + global::Virgil.SDK.Resource.String.Hello = global::Virgil.SDK.Tests.Droid.Resource.String.Hello; + global::Xamarin.Forms.Platform.Resource.String.ApplicationName = global::Virgil.SDK.Tests.Droid.Resource.String.ApplicationName; + global::Xamarin.Forms.Platform.Resource.String.Hello = global::Virgil.SDK.Tests.Droid.Resource.String.Hello; + } + + public partial class Attribute + { + + static Attribute() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + private Attribute() + { + } + } + + public partial class Mipmap + { + + // aapt resource value: 0x7f020000 + public const int Icon = 2130837504; + + static Mipmap() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + private Mipmap() + { + } + } + + public partial class String + { + + // aapt resource value: 0x7f030001 + public const int ApplicationName = 2130903041; + + // aapt resource value: 0x7f030000 + public const int Hello = 2130903040; + + static String() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + private String() + { + } + } + } +} +#pragma warning restore 1591 diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-hdpi/Icon.png b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-hdpi/Icon.png new file mode 100644 index 00000000..f4c80464 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-hdpi/Icon.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-mdpi/Icon.png b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-mdpi/Icon.png new file mode 100644 index 00000000..ef1e1ee7 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-mdpi/Icon.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xhdpi/Icon.png b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xhdpi/Icon.png new file mode 100644 index 00000000..b7e2e57a Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xhdpi/Icon.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxhdpi/Icon.png b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxhdpi/Icon.png new file mode 100644 index 00000000..8d20a38d Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxhdpi/Icon.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxxhdpi/Icon.png b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxxhdpi/Icon.png new file mode 100644 index 00000000..6d9919c4 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Droid/Resources/mipmap-xxxhdpi/Icon.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/SecureStorageTests.cs b/SDK/Source/Virgil.SDK.Tests.Droid/SecureStorageTests.cs new file mode 100644 index 00000000..9f099cf5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/SecureStorageTests.cs @@ -0,0 +1,123 @@ +using System; +using Bogus; +using NUnit.Framework; +using Virgil.SDK; +using Virgil.SDK.Storage; +using Virgil.SDK.Storage.Exceptions; + +namespace AndroidTestApp +{ + [TestFixture] + public class SecureStorageTests + { + private readonly Faker faker = new Faker(); + + [SetUp] + public void SetUp() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + } + + [Test] + public void Save_Should_SaveDataUnderKey() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storedData = storage.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void Save_Should_SaveDataBetweenSessions() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storage2 = new SecureStorage(passw); + + var storedData = storage2.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void SaveWithDuplicateKey_Should_RaiseDuplicateKeyException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + Assert.Throws( + () => storage.Save(key, data)); + storage.Delete(key); + } + + [Test] + public void LoadByMissingKey_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + + Assert.Throws( + () => storage.Load(key)); + } + + [Test] + public void DeleteByMissingKey_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + Assert.Throws( + () => storage.Delete(key)); + } + + [Test] + public void Keys_Should_ReturnAllSavedKeys() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = "my_key_1"; + var key2 = "my_key_2"; + + storage.Save(key, data); + storage.Save(key2, data); + var keys = storage.Aliases(); + Assert.AreNotEqual(Array.IndexOf(keys, key), -1); + Assert.AreNotEqual(Array.IndexOf(keys, key2), -1); + + storage.Delete(key); + storage.Delete(key2); + } + + [Test] + public void LoadByWrongPass_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + var data = faker.Random.Bytes(32); + storage.Save(key, data); + //change pass + var passw2 = faker.Random.Words(); + var storage2 = new SecureStorage(passw2); + Assert.Throws( + () => storage2.Load(key)); + storage.Delete(key); + } + + } + +} diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/Virgil.SDK.Tests.Droid.csproj b/SDK/Source/Virgil.SDK.Tests.Droid/Virgil.SDK.Tests.Droid.csproj new file mode 100644 index 00000000..545e3326 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/Virgil.SDK.Tests.Droid.csproj @@ -0,0 +1,159 @@ + + + + Debug + AnyCPU + {0FA9B741-3F82-4965-92C7-9E0895E80E5A} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Virgil.SDK.Tests.Droid + Virgil.SDK.Tests.Droid + v5.1 + True + Resources\Resource.designer.cs + Resource + Resources + Assets + false + Properties\AndroidManifest.xml + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + None + arm64-v8a;armeabi;armeabi-v7a;x86;x86_64 + + + true + pdbonly + true + bin\Release + prompt + 4 + true + false + armeabi-v7a;x86;arm64-v8a;x86_64;armeabi + + + + + + + ..\packages\Bogus.20.0.2\lib\netstandard2.0\Bogus.dll + + + + + ..\packages\System.Configuration.ConfigurationManager.4.4.1\lib\netstandard2.0\System.Configuration.ConfigurationManager.dll + + + ..\packages\FluentAssertions.4.2.2\lib\monoandroid\FluentAssertions.Core.dll + + + ..\packages\FluentAssertions.Xamarin.4.2.2\lib\monoandroid\FluentAssertions.dll + + + + + ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\Castle.Core.4.2.0\lib\netstandard1.3\Castle.Core.dll + + + ..\packages\NSubstitute.3.1.0\lib\netstandard1.3\NSubstitute.dll + + + ..\packages\PCLStorage.1.0.2\lib\monoandroid\PCLStorage.Abstractions.dll + + + ..\packages\PCLStorage.1.0.2\lib\monoandroid\PCLStorage.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\FormsViewGroup.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Platform.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll + + + ..\packages\Virgil.Crypto.2.2.5\lib\monoandroid\Virgil.Crypto.dll + + + + ..\packages\Newtonsoft.Json.10.0.3\lib\netstandard1.3\Newtonsoft.Json.dll + + + + ..\packages\Xamarin.Android.Support.v4.22.2.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll + + + ..\packages\NUnit.3.6.1\lib\MonoAndroid\nunit.framework.dll + + + ..\packages\nunit.xamarin.3.6.1\lib\MonoAndroid\nunit.runner.Droid.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\MonoAndroid10\PCLAppConfig.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\MonoAndroid10\PCLAppConfig.FileSystemStream.Abstractions.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\MonoAndroid10\PCLAppConfig.FileSystemStream.dll + + + + + + + + + + + + + + + + + + + + + + + + + + {6B9CE116-871B-4294-AA8E-64DE316AA79A} + Virgil.SDK.Droid + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Droid/packages.config b/SDK/Source/Virgil.SDK.Tests.Droid/packages.config new file mode 100644 index 00000000..de8e5a65 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Droid/packages.config @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/AppDelegate.cs b/SDK/Source/Virgil.SDK.Tests.Mac/AppDelegate.cs new file mode 100644 index 00000000..9c85ea31 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/AppDelegate.cs @@ -0,0 +1,59 @@ +using AppKit; +using Foundation; +using Security; +using Bogus; + +using Virgil.SDK.Storage; + +namespace Virgil.SDK.Tests.Mac +{ + [Register("AppDelegate")] + public class AppDelegate : NSApplicationDelegate + { + public AppDelegate() + { + var tests = new SecureStorageTests(); + Faker faker = new Faker(); + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storedData = storage.Load(key); + + + string st = ""; + var s = new SecRecord(SecKind.GenericPassword) + { + Label = "Item Label1", + Description = "Item description", + Account = "Account1", + Service = "ServiceTest", + Comment = "Your comment here" + }; + var c = s.AccessGroup; + s.ValueData = NSData.FromString("my-secret-password"); + var err = SecKeyChain.Add(s); + + if (err != SecStatusCode.Success && err != SecStatusCode.DuplicateItem) + { + st = "Error adding record: {0}"; + } + else + { + st = "you are done!!!"; + }; + } + + public override void DidFinishLaunching(NSNotification notification) + { + // Insert code here to initialize your application + } + + public override void WillTerminate(NSNotification notification) + { + // Insert code here to tear down your application + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/AppSettings.cs b/SDK/Source/Virgil.SDK.Tests.Mac/AppSettings.cs new file mode 100644 index 00000000..6a2a5363 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/AppSettings.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using Newtonsoft.Json; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests +{ + public class AppSettings + { + static AppSettings(){ + var cryptoTestData = File.ReadAllText("TestData/crypto_compatibility_data.json"); + AppSettings.CryptoCompatibilityData = cryptoTestData; + + } + + public static string AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + public static string AccounId = ConfigurationManager.AppSettings["virgil:AccountID"]; + public static string AppPrivateKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; + public static string ApiPublicKeyId = ConfigurationManager.AppSettings["virgil:AccessPublicKeyId"]; + public static string ApiPrivateKeyBase64 = ConfigurationManager.AppSettings["virgil:AccessPrivateKeyBase64"]; + public static string ServiceCardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"]; + public static string ServicePublicKeyPemBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyPemBase64"]; + public static string ServicePublicKeyDerBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"]; + public static string CryptoCompatibilityData = ""; + public static string OutputTestDataPath = ConfigurationManager.AppSettings["test:OutputDataPath"]; + public static string CardsServiceAddress = ConfigurationManager.AppSettings["virgil:CardsServicesAddressV5"]; + + public static string PrivateKeySTC31_1 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_1"]; + public static string PrivateKeySTC31_2 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_2"]; + public static string PublicKeySTC32 = ConfigurationManager.AppSettings["test:PublicKeySTC32"]; + + public static string ImportedAccessPublicKeyId = ConfigurationManager.AppSettings["test:ImportedAccessPublicKeyId"]; + public static string ImportedAccessPublicKey = ConfigurationManager.AppSettings["test:ImportedAccessPublicKey"]; + + public static string PredefinedPrivateKeyBase64 = ConfigurationManager.AppSettings["test:PredefinedPrivateKeyBase64"]; + + public static string ImportedJwt = ConfigurationManager.AppSettings["test:ImportedJwt"]; + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png new file mode 100644 index 00000000..d0b5a809 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png new file mode 100644 index 00000000..f4c8d290 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png new file mode 100644 index 00000000..ebb5a0fe Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png new file mode 100644 index 00000000..0986d31b Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png new file mode 100644 index 00000000..f4c8d290 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png new file mode 100644 index 00000000..a142c83f Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png new file mode 100644 index 00000000..0986d31b Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png new file mode 100644 index 00000000..412d6ca9 Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png new file mode 100644 index 00000000..a142c83f Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png new file mode 100644 index 00000000..e99022ae Binary files /dev/null and b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..6b285452 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images": [ + { + "filename": "AppIcon-16.png", + "size": "16x16", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-16@2x.png", + "size": "16x16", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-32.png", + "size": "32x32", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-32@2x.png", + "size": "32x32", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-128.png", + "size": "128x128", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-128@2x.png", + "size": "128x128", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-256.png", + "size": "256x256", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-256@2x.png", + "size": "256x256", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-512.png", + "size": "512x512", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-512@2x.png", + "size": "512x512", + "scale": "2x", + "idiom": "mac" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/Contents.json b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/Contents.json new file mode 100644 index 00000000..4caf392f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Entitlements.plist b/SDK/Source/Virgil.SDK.Tests.Mac/Entitlements.plist new file mode 100644 index 00000000..9ae59937 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Info.plist b/SDK/Source/Virgil.SDK.Tests.Mac/Info.plist new file mode 100644 index 00000000..45addec8 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Info.plist @@ -0,0 +1,33 @@ + + + + + CFBundleName + Virgil.SDK.Tests.Mac + CFBundleIdentifier + com.virgil11.Virgil-SDK-Tests-Mac + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.12 + CFBundleDevelopmentRegion + en + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + NSHumanReadableCopyright + ${AuthorCopyright:HtmlEncode} + NSPrincipalClass + NSApplication + NSMainStoryboardFile + Main + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + + diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Main.cs b/SDK/Source/Virgil.SDK.Tests.Mac/Main.cs new file mode 100644 index 00000000..c423a857 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Main.cs @@ -0,0 +1,13 @@ +using AppKit; + +namespace Virgil.SDK.Tests.Mac +{ + static class MainClass + { + static void Main(string[] args) + { + NSApplication.Init(); + NSApplication.Main(args); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Main.storyboard b/SDK/Source/Virgil.SDK.Tests.Mac/Main.storyboard new file mode 100644 index 00000000..300de13d --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Main.storyboard @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Test.cs b/SDK/Source/Virgil.SDK.Tests.Mac/Test.cs new file mode 100644 index 00000000..15af9f19 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Test.cs @@ -0,0 +1,103 @@ +using System; +using Virgil.SDK.Storage.Exceptions; +using Bogus; +using Virgil.SDK.Storage; +using NUnit.Framework; + +namespace Virgil.SDK.Tests.Mac +{ + [TestFixture] + public class SecureStorageTests + { + private readonly Faker faker = new Faker(); + + public void Save_Should_SaveDataUnderKey() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storedData = storage.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void Save_Should_SaveDataBetweenSessions() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storage2 = new SecureStorage(); + + var storedData = storage2.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void SaveWithDuplicateKey_Should_RaiseDuplicateKeyException() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + Assert.Throws( + () => storage.Save(key, data)); + storage.Delete(key); + } + + [Test] + public void LoadByMissingKey_Should_RaiseKeyNotFoundException() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var key = faker.Person.UserName; + + Assert.Throws( + () => storage.Load(key)); + } + + [Test] + public void DeleteByMissingKey_Should_RaiseKeyNotFoundException() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var key = faker.Person.UserName; + Assert.Throws( + () => storage.Delete(key)); + } + + [Test] + public void Keys_Should_ReturnAllSavedKeys() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = "my_key_1"; + var key2 = "my_key_2"; + + storage.Save(key, data); + storage.Save(key2, data); + var keys = storage.Aliases(); + Assert.AreNotEqual(Array.IndexOf(keys, key), -1); + Assert.AreNotEqual(Array.IndexOf(keys, key2), -1); + storage.Delete(key); + storage.Delete(key2); + } + + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Testdata/crypto_compatibility_data.json b/SDK/Source/Virgil.SDK.Tests.Mac/Testdata/crypto_compatibility_data.json new file mode 100644 index 00000000..d3d9385f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Testdata/crypto_compatibility_data.json @@ -0,0 +1,54 @@ +{ + "encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIFx8vNiUAME3rwAoVMyuZg/F14FcMF5WETOeEV3Zr8c7", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIBYgIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQg9b1JYQ61xgfxYN1lFZkPOlB7XDMd/rxcVk8r2MPGntMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB066Ul4v6X9zUXoHx8TxlgaQC8c6ayVchkItZDfRZGwTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMGtLjjW6Rl3JMCh5683PT5E1LDdaspCLUnBJjWarkRnbcrmMt8yqLle6H4QVeqvIhjBRMB0GCWCGSAFlAwQBKgQQrP3B71mD165GE5vhEomT7QQwy25y+b+4DEHPp1RLHatp7uJ4ZwXMrsawrj/TOlCmz0oGz91v19McaA+r1wIMCnukMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDDGYn3cJsIhBAHq4F4sC+6JJBMT3Jh3GcrDp/F7E0LPRVHEXf9GzfvlW3SOzfG56CsLOmjIdZoqQgne8VLHWUYMXQKDae3s3AQBuo7d7EytYtUAgdw==" + }, + "encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIKyyfp+ssJL6AkwndBWL6jOPgswH+BVDzxU8md6nA40t", + "MC4CAQAwBQYDK2VwBCIEIAFYY8PG8enCO6NdUv1UVnC65ryr2mrGV6QDlJEliv3y", + "MC4CAQAwBQYDK2VwBCIEIATkmvo7jh0syRtTg1mNfSJNvqB1V9/bEKijP+rmK5MO", + "MC4CAQAwBQYDK2VwBCIEIK7KLGRPADz3NKk4p0hq3q/wwqN5g08pzN0b9+0NbgXq", + "MC4CAQAwBQYDK2VwBCIEIOJIlOdeAygksA2Y4RHJBQ51emPtVW257jeWiwMnS3nQ", + "MC4CAQAwBQYDK2VwBCIEIPVooGKp/JArB4dD5LDDjHeIsbBkAfDfWNgzFoAYov1C", + "MC4CAQAwBQYDK2VwBCIEIFEaV3yA+7ui8SgHLVzjCY/ZLfc5m8FMHe6nzlV/fOk3", + "MC4CAQAwBQYDK2VwBCIEIHLc4yhkFXMceatKElNvmgIsixBc0KkRxEL/FmnhzJTx" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIJEQIBADCCCQoGCSqGSIb3DQEHA6CCCPswggj3AgECMYIIyDCCARUCAQKgIgQgAz7ucGlal9Ci/bo+cUwEjgCssJyXvV4BhxM3y6oKuk0wBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCSZsPUeZvdKO5SoLVXnujHqj2L3RnbtWCV8jd3J/Dq7DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMAYsEjCm0IZfJ2Zmv7Hqp+CAEm6XaHjcvEMx0usIlSMtS+Nv5ZFuJBbsrx7kGbncOTBRMB0GCWCGSAFlAwQBKgQQVbZvllp7v53v+5zQE1RdVwQwd4dIDBJWocDNkETlUeIvQ7dE3k/0KNsFg5QUXIWZ49/pfDDHZ4cyaBAxm4pTVDUgMIIBFQIBAqAiBCAKaQVVewI74Q1xvI3qFj99IInXXHQpYwvCJGaHM2a3WTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAJTbV4mwvvX9QMIp7ZeI4vULr20xFVvIidWm5f8VLLRrMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZwA6LAIeLvksS/kjjsf5u0ON6KOkE3Na+Gr1YUN7D89SlGxoPM3AGS5Np8IhVXvNMFEwHQYJYIZIAWUDBAEqBBCxoYn5gb9l0DT8bXU/g9CZBDCID58W78ALWYdwoNtINpRxKNxdo7cic16XEG6z9KWWs8mEumowndsNL2dZPFvLpLcwggEVAgECoCIEIAuNcSL1B0U0778/hDjLqPkwtE8jO9YcZfhIgMXHa+msMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXpjJEOd7Ay5Bk+sCHZxL0LqjG2WGL7XiDXYb5nonPcUwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDvNhxjgDfrUdd04KW24RsXYc1nqFidBUxw7p9ItEt7plwkNTs2bzkMpHe7ufTQc3AwUTAdBglghkgBZQMEASoEEJHRiqJIuGuewZQVOv9rqCwEMIdasg5OxHuw1PHDd4bMqL0V3+FmSzxevYVDHYu9+M6KDmdDsYD2TbTnze6qQ2MyKTCCARUCAQKgIgQgF7uvNtMIAur6T5hUk8YmA+wS5l4nA/r1lsdhE94H29MwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB5dQD12I+x/u+A6nbvHSKS8BN5HURHBrCI+GjAyTqXHTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMEZuhCp3UsxPAkB58kKEvD9cAKIbOSG3Y/B8gCQn6VStsUqd+hlgT8xuJe9ZlXIzpTBRMB0GCWCGSAFlAwQBKgQQtcAXjSkyM/p6ai/dHH1ITAQwitM226Beplv6WD4WJb0IJS+4tu1DQ0Yc9jMoPH2Bv9GlElD6Ru3Yt6uwFIeI9IcDMIIBFQIBAqAiBCAnDrtwjOuscTQEPxvwxEZMMNw4hlDChj4KrIE9vjm8+jAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMbosYfz7z/c88WONdyQ3WBBZHDhGTM9lQ+NaAGNm0ZFMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQw+z/kd8iFoSsJ6oodl647M+uAZMUHtpbAskFLSlVybwIcO8Yukg1z1zi/wmohbI5JMFEwHQYJYIZIAWUDBAEqBBAT6xH+f9z8B40iX3V+FG3XBDBcKWor27gd3tPfwMrx+K55I6fDMVQuh96IWTvqxpiIDkHQNWcraI8iijGbKYOm4WcwggEVAgECoCIEIGSLvD61SgkWz7l3Zw9/N4rIBkR6n9Qo7Cs21gCn7AVjMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAGC9LfF1yG5JrBwGLFq1qJlcRl+ChOFG7jyTN4PXfiTwwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDD6IHUf8BozheyYWRW9VlZiIUjVUL/6sj9rRx0qV6CZ5hgHs5IZhKRDSkY1fsia6xIwUTAdBglghkgBZQMEASoEEAR8+jPqogiQWEjgoQ5qp/8EMMQgyW7+Lpj9sVsXpw7hPKtJMcR7ycqGDibmQCUR5kv+I2qoB4CFcKepeUcyXweiPDCCARUCAQKgIgQg7K3yFDemud3MKRJJxWpd2bSWm7rWjwjv7nmfvOlP+xwwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBOY0OO75qvwmMGABvaF8OD4EvKO0Luq9HnwrlcDBYl0DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMCoDfRigXpu4jgqQJw5mq5SID+d6ey7bfGE27DQgpM++20wH0FVOk+pn5pEm3DKMkjBRMB0GCWCGSAFlAwQBKgQQ4ekdMtGF5pjpdrE/dqEZQAQwyg5JVAgoJYz4mokP5pxxpCZjxR1uHGby9stjwmdg7u8f10xhNMLrnwAQGBNCyBB2MIIBFQIBAqAiBCDx4+HMoUWy/zMQnEfOmK1IrftOktlCECCknqfJgIniyjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC/4OYAGOvfglstuwvmzMH0P897oW00UOJh8z9Oa4drkMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwuguHh66/rA23c1xW+Wrpjs0ZEBUiBxrrRvJeS/S1bKMDDwUHVK/Md9johoDMsbb7MFEwHQYJYIZIAWUDBAEqBBDvsCvGh4Md3BJrkbhjzwy7BDAbVyByTf2TeFeEqDywIfY/dQbQcMtmTD+2Bn/Y0HT1Z7ClAjrcKuxkB9W0Ys1L3FgwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMIe1v++T1huQVtzypcIEf22hv+SZqDTkIAjBWFv3ZouzgqZg9jHLYv6nA1IruM6OegDuBG4s/mm/PQ1bV8brJEZx5BwTuC/b03RhDs3j6LphSJ+8o" + }, + "sign_then_encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBjaHn6Z1QrXdAfRb034JoDhoXM+8hKYiQzQAg6+l419", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIICFQIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB0YhufvezF6W/834kAB7o5LPquTik/0qkMLRlmP7fEGjAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMID/2OZvTt0cClysYG6ZVlKfmEGEJLl12gLZ07qRo3qtm4ARwRoweHtedbzpdRefXjBRMB0GCWCGSAFlAwQBKgQQVdMd5xQjd2DE16rGrBTqIwQw4YxHOLiK8mvvH8cMIPsU0rpsM0fe+ohMnHCaW5ccTdgSMCOyVjaDUMqpl+KvIF4GMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDCZnr2AeX892Duem8KCBsDGBrTA7DBVWSVJHSUwtREFUQS1TSUdORVItSUSiIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwbgwVVklSR0lMLURBVEEtU0lHTkFUVVJFolUEUzBRMA0GCWCGSAFlAwQCAwUABEC9GjnFrMcTJ7YKj46bDyQQ/EEUzuePFOSPk8RKjrFDFCLfLkYH9gVdUCjGrVv07/FcuKEd9ZS86G4tUuh3F9gC7EEbYUtjCnPL31rWnAKeqi04gUq1wFLA1YdtOvAqjZUc1N3LQ+oiTo1ErCJKhRhugpApO2V3YLl/tsU3NbrqQv1rPwjA12G8" + }, + "sign_then_encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIAvWl/kgTqbXQ+cTytIUCZkfjOYv7W6g5eyawFabxScJ", + "MC4CAQAwBQYDK2VwBCIEICGXlHJDS+I7rrqawhJQOJ8XjgOCNasUQcWR6os5wYE4", + "MC4CAQAwBQYDK2VwBCIEIG0S2QFR6u0AOoj8jZhZSObL8NaguY/nVZYs1FVgDpI/", + "MC4CAQAwBQYDK2VwBCIEIGhP0N16y7vcZXNRnhkUyIXNIj90+Swg+w0LRzdDaCsd", + "MC4CAQAwBQYDK2VwBCIEINk1nCOxREjzxD06eprK790GoqNWtWuVAu0fOue9B6Pn" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgZ/5EW3CwoNqvth/AhFM99EUelekEMlGi6b58yOzdzUIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQAiNmc2Y/3No9n6K5HpV0Yj2kIJht68/Qxz2BPTZFcvkTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMIZcBiKH2K5DjF7SRqOELqNPZp4GD0jY4/LoP+1kVSUNWJFNogeUdpsclpktDlcYozBRMB0GCWCGSAFlAwQBKgQQNIzOge5YjNvC95QG3W2oZQQwaxnJRb7j0n5+Doqd4VwbjXHxnYuOpWLDORxdhQjtaWrf8zqcW57ejT5w9GubDjxOMIIBFQIBAqAiBCBsXBt9/JYionc7FscmmxLkYqzQBlugvte3tBgR9+eyADAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMDxkSWypMtiqVQ3avChkE9BP30ta0zctoS4WW0OKRDiMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwBmKs+uwujxGmZcBXVIMv8x2EwJLHkgybdFCrymxAkdcocbAUAR42b0CiecrTBtBqMFEwHQYJYIZIAWUDBAEqBBBnvbvZQTSrb1PaIPmJFox0BDAg9dLzHnUw/QV5lCSVv+tj7wx3ML0ZdXCN14Aielstx7wO2Ygg9ejJ6lzkSJNgJ9EwggEVAgECoCIEIG08tVe/WHb7d+FAaErZRgWQ6M18TWtx0/O1FWmUoKwFMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAMMR5Lljq+Y2g2cespAzlC23CvRJLFaHDsJJBPyWodeswGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDIp0Rh1wwAYb73+t3oiNAT09GspVhS78fwElGFnTtmHzxSER/ugaixuEgzmkD5SdowUTAdBglghkgBZQMEASoEEM5LxKaK2b1dXyt8JXMaWaAEMMmMXWBr3QEB6YaaWwQMpGUQz7M3ri7WPPHtdpFMY1R9wt1quWU2eeFna7n7tKj3mTCCARUCAQKgIgQgpmRIy7nlVoGTkJBOHqEjKdeEcnJu5ahqfjYWrg+Z8oIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBilNAblc9gZ3yzTZHrUaYCdn64Perqaf4YmZXn+/QYGzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMJq9vHZAV4zu0cH5aMvCzBw6HqfiX0kzs4DI2WWPMmExTHfxlqbqB32+kS36HqH/cTBRMB0GCWCGSAFlAwQBKgQQMKacxhPe+eXxZ+sUXSI8/wQwbolTTcvEYTewC7Tyz29pd+FYnT92VdCM1ciI94PywbqZUUCbi32aR0AG1t5geUswMIIBFQIBAqAiBCDC0TMYmYbdpCd0fO+UBsN8Oyix6Q7NNXzVxpua0kGAwTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAEtgpOVQm18owVuPctwdXbQ8iRv24HPf8i64fCbkB0i0MBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZZ7cnK2Sq/KsP54qcN/su+ZEdtJIMunexuXzM2/GtW3yFDm13EPARvEwLiD/qZUOMFEwHQYJYIZIAWUDBAEqBBDphHjyT3NaJV/Rq+r/x4cvBDDtY+WdlzXUsfEQvGp2fBwM8xI6sZRbk68gUuZpCjFICeVsD8pdiS4RrjjnPMY2h1MwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMtbmAUdn9qCGdQPOhoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCBn/kRbcLCg2q+2H8CEUz30RR6V6QQyUaLpvnzI7N3NQjBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQKaB09lKLNo5mLRLxl4S5nI0dbYxwGUYUzXXtdLXnWMf4fxCPR0USW1qyIQLVUeJmtIhET3R/VPhqRrPKsFzyQAB/jziUKj409ykG++1OQg2FE5XhMhQoiFhTf8Cxo2tDeOOXCeQCy1SiG5wYJVXkVXFFNN8b59rJEp8RTRnIR8OfV6MkJsZCS4=" + }, + "generate_signature": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBueB+DRjfF52AK7qTkUUhOEOJwNpzxkt3d00riD7QuI", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "signature": "MFEwDQYJYIZIAWUDBAIDBQAEQAp6LhuwBbtq2UILTQpvlBy+0rPgB9bNP45rU03arAogObdXGRD9bzEob7LzQNE8BWNF/JQY+pL0pC5Z3qH6tAc=" + }, + "sign_then_encrypt_multiple_signers": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIG6wyMA56aGMaKf8kaDqo7j/5onSM3SN6Do5q3P28Xzp", + "public_keys": [ + "MCowBQYDK2VwAyEALSCsIR2pEK5SWR8k1kOqCjkLM7SEoMS98vO4TJ6GMC4=", + "MCowBQYDK2VwAyEA2AsShcg1ZpK5PdUsDpcRKXjs1BMcNb6jHxZ5cD0jYC8=", + "MCowBQYDK2VwAyEA2EOIbFIMSDdd5PebefEH5bAdGqeyFWaBDyKntr8SG2k=", + "MCowBQYDK2VwAyEAZoH5Fn31VuT7xClvY3cLoNMkSQqeR8fPxAEUERFYdSQ=", + "MCowBQYDK2VwAyEAVBmCMI5YvsyCDQv5gyZhm+uWyHTnhILe/K9CNKUqkLw=" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgV+lgOdbbR8aHUjIEx/YblRLUe/bGcH48E86p0I45JkMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCAIRQh5ho70Jl3wuIpZxMv7bRzWgZDoBFtZafbiXCp2jAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMNPkFuMoCS/A9nzgZQ5lie5laQnGcfPYZVm6iwxual6USPOF6oqZd0EJu2xKx188IzBRMB0GCWCGSAFlAwQBKgQQd1cWGby4gwQgB8MTRmQxwgQweMtdoScv4IEQu0jwTXgasA3LvgUOiIAeSvUSdiYlh55Vx6sTe7cXjoheLKclSWgLMIIBFQIBAqAiBCB06AofjB8oEBQU0dRxXdJsbOSUq7Xscawaz29Akghv+DAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC8xBHqoj3SJ3lnrZRi4sKrLpAEv53VuyFeyyZr5parBMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwd/+fkUJ92w1AxbBGEtOZUQXVKplYlbfgZVxTdwPFEFaVxHkRf2DFLjYcA8eJxl+mMFEwHQYJYIZIAWUDBAEqBBB2sx1N39H6gkHGSSDxSWM+BDDQXM5d9avTHrLEzOOwWe3vtpFxkefz0/8T06c3UMxvhMp/TM3xYXgSQ1dDrDuMAVowggEVAgECoCIEIK8P8zsSxEpPs/6UDFfKP3/pz/Gas6c1VMnv7xUOhQVbMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXjeOtEDF+FzRvyGoKlUwfuC+cbGonXmQ1lfbvClLHYMwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDBSEicWwBP9gcdwbi3TlsX3YMWs3ue18iUUltu05uFruh+c2xYwTwo2Zt+oPNHT+mYwUTAdBglghkgBZQMEASoEEJaLW/UPxiYD1z4RQh0qMxMEMKVsy7VquNAYLvuaFdYJszzz5HtqlC9OnCiEOc9gecKL8KQ3bU0l4vL4pFl7SgBCJzCCARUCAQKgIgQgz3bkz4SRK/ndLceAz5A1rc4QpUdQsOKSg8Lpg9Yd29swBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCjOgxFr+VCWdngH0SQMu6bfcUFqWooDGDut0G0t7RSEzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMKADb3wAPzdJ+BsuKBB59pdL3HpV/hCRGtZtzHqfiIdTFsv+kMczigySgKGvysJrKzBRMB0GCWCGSAFlAwQBKgQQ/uq+33Aivg92/9lpF8feHQQwILYYaJz55qTzFwLe21a+oo9av0A/7mNBkqW4ogGn4/fOJ4T2Pwlt8kZor033rBHkMIIBFQIBAqAiBCDX7SnuiYY1nMfPaqFGbEssf4GXA3LlB97QLjJ+CjlazjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAHnBZCXOZ365uuylYUJcsG91xVq46zmnAKkDRI3uOAATMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwM/lDhsv7B0Qq45Zi9pP7oKrlhzhtYlNk8Wh1uKA9mBWLqVQ61NlQVm9F2gk1gpPsMFEwHQYJYIZIAWUDBAEqBBDBBGvJ5lNVVw9/2/JU9ZHSBDA8y9XblGHB40qIniw+TeAt87peZP/mCYd4NCk91wt3perCNMhEJhoBq3KnB91Lyq4wJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMXnmCLfBKuPnH+nxmoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCDPduTPhJEr+d0tx4DPkDWtzhClR1Cw4pKDwumD1h3b2zBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQMbcL2CbQYHafMsmut9uyZ1c4cJGWk2cQZDZ8xcb/4EXeo/cJxFDhc59TVtjIImy8L4xpVLuI6+wGfwGIPmZKwlJubsUEUn+KHvHlS4z41YCsDrxXaDN8luv5jj+ERJg9MVrHttjMTOX0IIVoxcylbi6V2wd7/+KiL0JKx3dV5syJ4by+Y0y6eY=" + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.cs b/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.cs new file mode 100644 index 00000000..a2cd2432 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.cs @@ -0,0 +1,34 @@ +using System; + +using AppKit; +using Foundation; + +namespace Virgil.SDK.Tests.Mac +{ + public partial class ViewController : NSViewController + { + public ViewController(IntPtr handle) : base(handle) + { + } + + public override void ViewDidLoad() + { + base.ViewDidLoad(); + + // Do any additional setup after loading the view. + } + + public override NSObject RepresentedObject + { + get + { + return base.RepresentedObject; + } + set + { + base.RepresentedObject = value; + // Update the view, if already loaded. + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.designer.cs b/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.designer.cs new file mode 100644 index 00000000..33ad362d --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/ViewController.designer.cs @@ -0,0 +1,18 @@ +// WARNING +// +// This file has been generated automatically by Xamarin Studio to store outlets and +// actions made in the UI designer. If it is removed, they will be lost. +// Manual changes to this file may not be handled correctly. +// +using Foundation; + +namespace Virgil.SDK.Tests.Mac +{ + [Register("ViewController")] + partial class ViewController + { + void ReleaseDesignerOutlets() + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/Virgil.SDK.Tests.Mac.csproj b/SDK/Source/Virgil.SDK.Tests.Mac/Virgil.SDK.Tests.Mac.csproj new file mode 100644 index 00000000..85db57e5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/Virgil.SDK.Tests.Mac.csproj @@ -0,0 +1,148 @@ + + + + Debug + x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6} + {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Virgil.SDK.Tests.Mac + Virgil.SDK.Tests.Mac + v2.0 + Xamarin.Mac + Resources + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + Mac Developer + false + false + false + true + true + x64 + HttpClientHandler + Full + x86_64 + + + + pdbonly + true + bin\Release + + prompt + 4 + false + true + false + true + true + true + SdkOnly + x64 + HttpClientHandler + + + + + + + + + + ..\packages\Bogus.21.0.5\lib\netstandard2.0\Bogus.dll + + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\Castle.Core.4.2.0\lib\netstandard1.3\Castle.Core.dll + + + ..\packages\NSubstitute.3.1.0\lib\netstandard1.3\NSubstitute.dll + + + ..\packages\Newtonsoft.Json.11.0.1-beta3\lib\netstandard2.0\Newtonsoft.Json.dll + + + ..\packages\Virgil.Crypto.2.2.5\lib\xamarinmac\Virgil.Crypto.dll + + + ..\packages\System.Configuration.ConfigurationManager.4.4.0\lib\netstandard2.0\System.Configuration.ConfigurationManager.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ViewController.cs + + + + + + + + + + {D4FDF98B-0EF0-47E3-ABCF-675CECC0C22D} + Virgil.SDK.Mac + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Mac/packages.config b/SDK/Source/Virgil.SDK.Tests.Mac/packages.config new file mode 100644 index 00000000..02e740ab --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Mac/packages.config @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenBuilderTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenBuilderTests.cs new file mode 100644 index 00000000..dd948fd5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenBuilderTests.cs @@ -0,0 +1,11 @@ +using NUnit.Framework; + +namespace Virgil.SDK.Tests +{ + + [NUnit.Framework.TestFixture] + public class AccessTokenBuilderTests + { + + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenProviderTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenProviderTests.cs new file mode 100644 index 00000000..29bf85df --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/AccessTokenProviderTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Bogus; +using NUnit.Framework; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests.Shared +{ + [TestFixture] + public class AccessTokenProviderTests + { + private readonly Faker faker = new Faker(); + + [Test] + public async Task GetTokenAsync_Should_ReturnNewTokenEachTime_IfUserHasNotImplementedCashInObtainTokenFuncAsync() + { + Func> obtainToken = async (TokenContext tokenContext) => + { + var jwtFromServer = await IntegrationHelper.EmulateServerResponseToBuildTokenRequest(tokenContext); + return jwtFromServer; + }; + var callBackProvider = new CallbackJwtProvider(obtainToken); + var context = new TokenContext(faker.Random.AlphaNumeric(20), "some_operation"); + var token1 = await callBackProvider.GetTokenAsync(context); + var token2 = await callBackProvider.GetTokenAsync(context); + Assert.AreNotEqual(token1, token2); + } + + [Test] + public void GetTokenAsync_Should_RaiseException_IfObtainTokenFuncReturnsInvalidString() + { + Func> obtainToken = async (TokenContext tokenContext) => + { + var jwtFromServer = await Task.Factory.StartNew(() => + { + return faker.Random.AlphaNumeric(30); + }); ; + return jwtFromServer; + }; + var callBackProvider = new CallbackJwtProvider(obtainToken); + var context = new TokenContext(faker.Random.AlphaNumeric(20), "some_operation"); + Assert.ThrowsAsync( + async () => await callBackProvider.GetTokenAsync(context)); + } + + [Test] + public async Task GetTokenAsync_Should_ReturnTheSameToken_InConstAccessTokenProviderAsync() + { + var jwtFromServer = await IntegrationHelper.EmulateServerResponseToBuildTokenRequest( + new TokenContext(faker.Random.AlphaNumeric(20), "some_operation") + ); + var jwt = new Jwt(jwtFromServer); + var constAccessTokenProvider = new ConstAccessTokenProvider(jwt); + var token1 = await constAccessTokenProvider.GetTokenAsync( + new TokenContext( + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(10), + true) + ); + + var token2 = await constAccessTokenProvider.GetTokenAsync( + new TokenContext( + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(10), + true) + ); + + Assert.AreEqual(token1, token2); + } + + [Test] + public async Task ImportedJwt_Should_BeTheSameAsOrigin() + { + Func> obtainToken = async (TokenContext tokenContext) => + { + var jwtFromServer = await IntegrationHelper.EmulateServerResponseToBuildTokenRequest(tokenContext); + return jwtFromServer; + }; + var callBackProvider = new CallbackJwtProvider(obtainToken); + var context = new TokenContext(faker.Random.AlphaNumeric(20), "some_operation"); + var token = await callBackProvider.GetTokenAsync(context); + + var importedJwt = new Jwt(token.ToString()); + Assert.AreEqual(importedJwt.ToString(), token.ToString()); + Assert.AreEqual(importedJwt.BodyContent.Identity, ((Jwt)token).BodyContent.Identity); + Assert.AreEqual(importedJwt.BodyContent.AdditionalData, ((Jwt)token).BodyContent.AdditionalData); + Assert.AreEqual(importedJwt.BodyContent.AppId, ((Jwt)token).BodyContent.AppId); + Assert.AreEqual(importedJwt.BodyContent.ExpiresAt, ((Jwt)token).BodyContent.ExpiresAt); + Assert.AreEqual(importedJwt.BodyContent.IssuedAt, ((Jwt)token).BodyContent.IssuedAt); + Assert.AreEqual(importedJwt.BodyContent.Subject, ((Jwt)token).BodyContent.Subject); + Assert.AreEqual(importedJwt.BodyContent.Issuer, ((Jwt)token).BodyContent.Issuer); + + + Assert.AreEqual(importedJwt.HeaderContent.Algorithm, ((Jwt)token).HeaderContent.Algorithm); + Assert.AreEqual(importedJwt.HeaderContent.KeyId, ((Jwt)token).HeaderContent.KeyId); + Assert.AreEqual(importedJwt.HeaderContent.ContentType, ((Jwt)token).HeaderContent.ContentType); + Assert.AreEqual(importedJwt.HeaderContent.Type, ((Jwt)token).HeaderContent.Type); + + Assert.IsTrue(importedJwt.SignatureData.SequenceEqual(((Jwt)token).SignatureData)); + + + } + + + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/BytesConvertTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/BytesConvertTests.cs new file mode 100644 index 00000000..6ebbf2e4 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/BytesConvertTests.cs @@ -0,0 +1,101 @@ +namespace Virgil.SDK.Tests +{ + using System; + using System.Text; + using Bogus; + using NUnit.Framework; + + using Virgil.SDK.Common; + + [TestFixture] + public class BytesConvertTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void ToString_Should_ConvertByteArrayToUTF8EncodedString_InCaseStringEncodingTypeNotProvided() + { + const string text = "Hello UTF8"; + var bytes = Encoding.UTF8.GetBytes(text); + + var encodedString = Bytes.ToString(bytes); + Assert.AreEqual(encodedString, text); + } + + [Test] + public void ToString_Should_ConvertByteArrayToBASE64EncodedString_ByGivenBASE64StringEncodingTypeAsParameter() + { + var randomBytes = this.faker.Random.Bytes(100); + + var encodedString = Bytes.ToString(randomBytes, StringEncoding.BASE64); + Assert.AreEqual(encodedString, Convert.ToBase64String(randomBytes)); + } + + [Test] + public void ToString_Should_ConvertByteArrayToUTF8EncodedString_ByGivenUTF8StringEncodingTypeAsParameter() + { + var randomBytes = this.faker.Random.Bytes(100); + + var encodedString = Bytes.ToString(randomBytes); + Assert.AreEqual(encodedString, Encoding.UTF8.GetString(randomBytes)); + } + + [Test] + public void ToString_Should_ConvertByteArrayToNotSeporatedLovercaseHexString_ByGivenHEXStringEncodingTypeAsParameter() + { + var randomBytes = this.faker.Random.Bytes(100); + + var encodedString = Bytes.ToString(randomBytes, StringEncoding.HEX); + Assert.AreEqual(encodedString, BitConverter.ToString(randomBytes).Replace("-", "").ToLower()); + } + + [Test] + public void FromString_Should_ConvertUTF8EncodedStringToByteArray_InCaseStringEncodingTypeNotProvided() + { + const string text = "Hello UTF8"; + var bytes = Encoding.UTF8.GetBytes(text); + + var decodedBytes = Bytes.FromString(text); + Assert.AreEqual(decodedBytes, bytes); + } + + + [Test] + public void FromString_Should_ConvertBASE64EncodedStringToByteArray_ByGivenBASE64StringEncodingTypeAsParameter() + { + var randomBytes = this.faker.Random.Bytes(100); + var base64 = Convert.ToBase64String(randomBytes); + Assert.AreEqual(Bytes.FromString(base64, StringEncoding.BASE64), randomBytes); + } + + [Test] + public void FromString_Should_ConvertUTF8EncodedStringToByteArray_ByGivenUTF8StringEncodingTypeAsParameter() + { + var sbytes = Encoding.UTF8.GetBytes("some text"); + // We can't use random bytes because of potential valid character which UTF8 can replace by 'replacement' character. + var utf8 = Encoding.UTF8.GetString(sbytes); + Assert.AreEqual(Bytes.FromString(utf8, StringEncoding.UTF8), sbytes); + } + + [Test] + public void FromString_Should_ConvertHexEncodedStringToByteArray_ByGivenHEXStringEncodingTypeAsParameter() + { + var randomBytes = this.faker.Random.Bytes(100); + var hex = BitConverter.ToString(randomBytes).Replace("-", "").ToLower(); + Assert.AreEqual(Bytes.FromString(hex, StringEncoding.HEX), randomBytes); + } + + [Test] + public void FromNullString_Should_RaiseArgumentNullException() + { + Assert.Throws( + () => Bytes.FromString(null, StringEncoding.UTF8)); + } + [Test] + public void ToString_Should_RaiseArgumentNullException() + { + Assert.Throws( + () => Bytes.ToString(null, StringEncoding.HEX)); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/CardIdGeneratorTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/CardIdGeneratorTests.cs new file mode 100644 index 00000000..884849c4 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/CardIdGeneratorTests.cs @@ -0,0 +1,26 @@ +using System.Linq; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests +{ + using Bogus; + using NUnit.Framework; + + [TestFixture] + public class CardIdGeneratorTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void Generate_Should_ReturnHexStringOf32SHA512() + { + var cardCrypto = new VirgilCardCrypto(); + var payload = this.faker.Random.Bytes(64); + var sha512 = cardCrypto.GenerateSHA512(payload); + var id = Bytes.ToString(sha512.Take(32).ToArray(), StringEncoding.HEX); + + Assert.AreEqual(id, CardUtils.GenerateCardId(cardCrypto, payload)); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/CardManagerTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/CardManagerTests.cs new file mode 100644 index 00000000..c7458c87 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/CardManagerTests.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; +using Virgil.SDK.Verification; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests +{ + using Bogus; + using NUnit.Framework; + using System.Linq; + using System.Threading.Tasks; + using Virgil.CryptoAPI; + using Virgil.SDK.Web; + using NSubstitute; + using Virgil.CryptoImpl; + + [NUnit.Framework.TestFixture] + public class CardManagerTests + { + private readonly Faker faker = new Faker(); + + + [Test] + public async Task CreateCard_Should_RegisterNewCardOnVirgilSerivice() + { + var card = await IntegrationHelper.PublishCard("alice-" + Guid.NewGuid()); + Assert.AreNotEqual(card, null); + var gotCard = await IntegrationHelper.GetCard(card.Id); + Assert.IsTrue(card.ContentSnapshot.SequenceEqual(gotCard.ContentSnapshot)); + Assert.IsTrue(card.Signatures.First( + x => x.Signer == ModelSigner.SelfSigner).Signature.SequenceEqual( + gotCard.Signatures.First(x => x.Signer == ModelSigner.SelfSigner).Signature) + ); + Assert.AreEqual(gotCard.Signatures.Count, 2); + } + + + [Test] + public async Task CreateCardWithPreviousCardId_Should_RegisterNewCardAndFillPreviouscardId() + { + // chain of cards for alice + var aliceName = "alice-" + Guid.NewGuid(); + var aliceCard = await IntegrationHelper.PublishCard(aliceName); + // override previous alice card + var newAliceCard = await IntegrationHelper.PublishCard(aliceName, aliceCard.Id); + Assert.AreEqual(newAliceCard.PreviousCardId, aliceCard.Id); + } + + [Test] + public async Task PreviousCardId_Should_BeOutdated() + { + // chain of cards for alice + var aliceName = "alice-" + Guid.NewGuid(); + var aliceCard = await IntegrationHelper.PublishCard(aliceName); + // override previous alice card + var newAliceCard = await IntegrationHelper.PublishCard(aliceName, aliceCard.Id); + var outdatedCard = await IntegrationHelper.GetCard(aliceCard.Id); + Assert.IsTrue(outdatedCard.IsOutdated); + var esearch = await IntegrationHelper.SearchCardsAsync("lalala"); + } + + [Test] + public async Task SearchCardByIdentityWhichHasTwoRelatedCards_Should_ReturnOneActualCard() + { + // chain of cards for alice + var aliceName = "alice-" + Guid.NewGuid(); + var aliceCard = await IntegrationHelper.PublishCard(aliceName); + // override previous alice card + var newAliceCard = await IntegrationHelper.PublishCard(aliceName, aliceCard.Id); + var cards = await IntegrationHelper.SearchCardsAsync(aliceName); + Assert.AreEqual(cards.Count, 1); + var actualCard = cards.First(); + Assert.AreEqual(actualCard.Id, newAliceCard.Id); + Assert.AreEqual(actualCard.PreviousCard.Id, aliceCard.Id); + Assert.IsTrue(actualCard.PreviousCard.IsOutdated); + } + + [Test] + public async Task SearchCardByIdentityWhichHasTwoUnrelatedCards_Should_ReturnTwoActualCards() + { + // list of cards for bob + var bobName = "bob-" + Guid.NewGuid(); + // create two independent cards for bob + await IntegrationHelper.PublishCard(bobName); + await IntegrationHelper.PublishCard(bobName); + + var bobCards = await IntegrationHelper.SearchCardsAsync(bobName); + Assert.AreEqual(bobCards.Count, 2); + } + + [Test] + public void CreateCardWithInvalidPreviousCardId_Should_RaiseException() + { + var aliceName = "alice-" + Guid.NewGuid(); + Assert.ThrowsAsync( + async () => await IntegrationHelper.PublishCard(aliceName, "InvalidPreviousCardId")); + } + + [Test] + public async Task CreateCardWithNonuniquePreviousCardId_Should_RaiseExceptionAsync() + { + var aliceName = "alice-" + Guid.NewGuid(); + var prevCard = await IntegrationHelper.PublishCard(aliceName); + // first card with previous_card + await IntegrationHelper.PublishCard(aliceName, prevCard.Id); + // second card with the same previous_card + Assert.ThrowsAsync( + async () => await IntegrationHelper.PublishCard(aliceName, prevCard.Id)); + } + [Test] + public async Task CreateCardWithWrongIdentityInPreviousCard_Should_RaiseExceptionAsync() + { + var aliceName = "alice-" + Guid.NewGuid(); + var prevCard = await IntegrationHelper.PublishCard(aliceName); + // identity and identity of previous card shouldn't be different + Assert.ThrowsAsync( + async () => await IntegrationHelper.PublishCard($"new-{aliceName}", prevCard.Id)); + } + + [Test] + public void GetCardWithWrongId_Should_RaiseException() + { + Assert.ThrowsAsync( + async () => await IntegrationHelper.GetCard("InvalidCardId")); + } + + [Test] + public async Task SearchCardWithWrongIdentity_Should_ReturnEmptyList() + { + var cards = await IntegrationHelper.SearchCardsAsync("someidentity1"); + Assert.AreEqual(cards.Count, 0); + } + + [Test] + public async Task SearchCards_Should_ReturnTheSameCard() + { + var aliceName = "alice-" + Guid.NewGuid(); + var card = await IntegrationHelper.PublishCard(aliceName); + var aliceCards = await IntegrationHelper.SearchCardsAsync(aliceName); + Assert.AreEqual(aliceCards.Count, 1); + Assert.AreEqual(aliceCards.First().Id, card.Id); + } + + + [Test] + public void ImportPureCardFromString_Should_CreateEquivalentCard() + { + //STC-3 + var rawSignedModel = faker.PredefinedRawSignedModel(); + var cardManager = faker.CardManager(); + var str = rawSignedModel.ExportAsString(); + var card = cardManager.ImportCardFromString(str); + var exportedCardStr = cardManager.ExportCardAsString(card); + Assert.AreEqual(exportedCardStr, str); + } + + [Test] + public void ImportPureCardFromJson_Should_CreateEquivalentCard() + { + //STC-3 + var rawSignedModel = faker.PredefinedRawSignedModel(); + var cardManager = faker.CardManager(); + var json = rawSignedModel.ExportAsJson(); + var card = cardManager.ImportCardFromJson(json); + var exportedCardJson = cardManager.ExportCardAsJson(card); + Assert.AreEqual(exportedCardJson, json); + } + + + + [Test] + public void ImportFullCardFromString_Should_CreateEquivalentCard() + { + //STC-4 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, true); + var cardManager = faker.CardManager(); + var str = rawSignedModel.ExportAsString(); + var card = cardManager.ImportCardFromString(str); + var exportedCardStr = cardManager.ExportCardAsString(card); + Assert.AreEqual(exportedCardStr, str); + } + + [Test] + public void ImportFullCardFromJson_Should_CreateEquivalentCard() + { + //STC-4 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, true); + var cardManager = faker.CardManager(); + var json = rawSignedModel.ExportAsJson(); + var card = cardManager.ImportCardFromJson(json); + var exportedCardJson = cardManager.ExportCardAsJson(card); + + Assert.AreEqual(exportedCardJson, json); + } + [Test] + public void CardManager_Should_RaiseException_IfExpiredToken() + { + // STC-26 + var jwtGenerator = new JwtGenerator( + faker.AppId(), + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.Zero, + Substitute.For()); + var accessTokenProvider = Substitute.For(); + accessTokenProvider.GetTokenAsync(Arg.Any()).Returns( + jwtGenerator.GenerateToken(faker.Random.AlphaNumeric(20)) + ); + var cardManager = faker.CardManager(accessTokenProvider); + + Assert.ThrowsAsync( + async () => await cardManager.GetCardAsync(faker.CardId())); + } + + [Test] + public async Task CardManager_Should_SendSecondRequestToCliet_IfTokenExpiredAndRetryOnUnauthorizedAsync() + { + // STC-26 + var expiredJwtGenerator = new JwtGenerator( + faker.AppId(), + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.Zero, + Substitute.For()); + + var jwtGenerator = new JwtGenerator( + AppSettings.AppId, + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.FromMinutes(10), + new VirgilAccessTokenSigner() + ); + var identity = faker.Random.AlphaNumeric(20); + var accessTokenProvider = Substitute.For(); + // suppose we have got expired token at the first attempt + // and we have got valid token at the second attempt + accessTokenProvider.GetTokenAsync(Arg.Any() + ).Returns( + args => + ((TokenContext)args[0]).ForceReload ? + jwtGenerator.GenerateToken(identity) : + expiredJwtGenerator.GenerateToken(identity) + ); + var validator = new VirgilCardVerifier(new VirgilCardCrypto()) { VerifySelfSignature = true, VerifyVirgilSignature = true }; + validator.ChangeServiceCreds(AppSettings.ServicePublicKeyDerBase64); + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = new VirgilCardCrypto(), + AccessTokenProvider = accessTokenProvider, + ApiUrl = AppSettings.CardsServiceAddress, + RetryOnUnauthorized = true, + Verifier = validator + }); + + var keypair = new VirgilCrypto().GenerateKeys(); + + var card = await manager.PublishCardAsync( + new CardParams() + { + Identity = identity, + PublicKey = keypair.PublicKey, + PrivateKey = keypair.PrivateKey + + }); + Assert.NotNull(card); + var searchCard = await manager.SearchCardsAsync(identity); + Assert.AreEqual(searchCard.Count, 1); + + var getCard = await manager.GetCardAsync(card.Id); + Assert.NotNull(getCard); + } + + + [Test] + public void CardManager_Should_RaiseExceptionIfGetsInvalidCard() + { + // STC-13 + var verifier = Substitute.For(); + verifier.VerifyCard(Arg.Any()).Returns(false); + + var signCallBack = Substitute.For>>(); + signCallBack.Invoke(Arg.Any()).Returns(args => (RawSignedModel)args[0]); + var jwtGenerator = new JwtGenerator( + faker.AppId(), + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.FromMinutes(10), + new VirgilAccessTokenSigner() + ); + var accessTokenProvider = Substitute.For(); + var identity = faker.Random.AlphaNumeric(20); + var token = jwtGenerator.GenerateToken(identity); + accessTokenProvider.GetTokenAsync(Arg.Any()).Returns( + token + ); + var model = faker.PredefinedRawSignedModel(null, true, true, true); + + var client = Substitute.For(); + Func>> getStub = async () => + { + return new Tuple(model, false); + }; + Func> publishStub = async () => + { + return model; + }; + Func>> searchStub = async () => + { + return new List() {model}; + }; + client.GetCardAsync(Arg.Any(), Arg.Any()).Returns(getStub.Invoke()); + client.PublishCardAsync(Arg.Any(), Arg.Any()).Returns(publishStub.Invoke()); + client.SearchCardsAsync(Arg.Any(), Arg.Any()).Returns(searchStub.Invoke()); + + var cardId = faker.CardId(); + var searchCardIdentity = faker.Random.AlphaNumeric(20); + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = new VirgilCardCrypto(), + AccessTokenProvider = accessTokenProvider, + SignCallBack = signCallBack, + Verifier = verifier, + ApiUrl = AppSettings.CardsServiceAddress + } + ){Client = client}; + Assert.Throws(() => manager.ImportCardFromJson(model.ExportAsJson())); + Assert.Throws(() => manager.ImportCardFromString(model.ExportAsString())); + Assert.ThrowsAsync(async () => await manager.GetCardAsync(cardId)); + Assert.ThrowsAsync(async () => await manager.PublishCardAsync(model)); + Assert.ThrowsAsync(async () => await manager.SearchCardsAsync(searchCardIdentity)); + Assert.Throws(() => manager.ImportCard(model)); + } + + [Test] + public void CardManager_Should_RaiseExceptionIfGetsCardWithDifferentId() + { + // STC-34 + var verifier = Substitute.For(); + verifier.VerifyCard(Arg.Any()).Returns(true); + var crypto = new VirgilCrypto(); + var keyPair = faker.PredefinedKeyPair(); + var rawCardContent = new RawCardContent() + { + CreatedAt = DateTime.UtcNow, + Identity = "test", + PublicKey = crypto.ExportPublicKey(keyPair.PublicKey), + Version = "5.0" + }; + var model = new RawSignedModel() { ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent) }; + + var signer = new ModelSigner(new VirgilCardCrypto()); + signer.SelfSign( + model, keyPair.PrivateKey, new Dictionary(){{ "info", "some_additional_info" }} + ); + var signCallBack = Substitute.For>>(); + signCallBack.Invoke(Arg.Any()).Returns(args => (RawSignedModel)args[0]); + var jwtGenerator = new JwtGenerator( + AppSettings.AppId, + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.FromMinutes(10), + new VirgilAccessTokenSigner() + ); + var accessTokenProvider = Substitute.For(); + var identity = faker.Random.AlphaNumeric(20); + var token = jwtGenerator.GenerateToken(identity); + accessTokenProvider.GetTokenAsync(Arg.Any()).Returns( + token + ); + var cardId = faker.CardId(); + var client = Substitute.For(); + Func>> stub = async () => + { + return new Tuple(model, false); + }; + client.GetCardAsync(Arg.Any(), Arg.Any()).Returns(stub.Invoke()); + + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = new VirgilCardCrypto(), + AccessTokenProvider = accessTokenProvider, + SignCallBack = signCallBack, + Verifier = verifier, + ApiUrl = AppSettings.CardsServiceAddress + } + ){Client = client}; + Assert.ThrowsAsync(async () => await manager.GetCardAsync(cardId)); + + } + + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/CardsClientTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/CardsClientTests.cs new file mode 100644 index 00000000..f3570be4 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/CardsClientTests.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Bogus; +using NSubstitute; +using NUnit.Framework; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; +using Virgil.SDK.Web; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests.Shared +{ + [TestFixture] + public class CardsClientTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void PublishCard_Should_RaiseExceptionIfTokenSignedByWrongKey() + { + var identity = faker.Random.AlphaNumeric(15); + var jwt = JwtSignedByWrongApiKey(identity); + var client = new CardClient(AppSettings.CardsServiceAddress); + Assert.ThrowsAsync( + async () => await client.PublishCardAsync(GenerateRawSignedModel(identity), jwt.ToString())); + } + + private RawSignedModel GenerateRawSignedModel(string identity) + { + var crypto = new VirgilCrypto(); + var keyPair = faker.PredefinedKeyPair(); + var rawCardContent = new RawCardContent() + { + CreatedAt = DateTime.UtcNow, + Identity = identity, + PublicKey = crypto.ExportPublicKey(keyPair.PublicKey), + Version = "5.0" + }; + var model = new RawSignedModel() {ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent)}; + + var signer = new ModelSigner(new VirgilCardCrypto()); + signer.SelfSign(model, keyPair.PrivateKey); + return model; + } + + [Test] + public void GetCard_Should_RaiseExceptionIfTokenSignedByWrongKey() + { + var jwt = JwtSignedByWrongApiKey(faker.Random.AlphaNumeric(15)); + var client = new CardClient(AppSettings.CardsServiceAddress); + Assert.ThrowsAsync( + async () => await client.GetCardAsync(faker.CardId(), jwt.ToString())); + } + + [Test] + public void SearchCard_Should_RaiseExceptionIfTokenSignedByWrongKeyAsync() + { + var jwt = JwtSignedByWrongApiKey(faker.Random.AlphaNumeric(15)); + var client = new CardClient(AppSettings.CardsServiceAddress); + Assert.ThrowsAsync( + async() => await client.SearchCardsAsync(faker.Random.AlphaNumeric(20), jwt.ToString())); + } + + [Test] + public void PublishCard_Should_RaiseExceptionIfTokenIdentityDiffersFromModelIdentity() + { + var jwt = GenerateJwt( + faker.Random.AlphaNumeric(15), + (PrivateKey)IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId + ); + var client = new CardClient(AppSettings.CardsServiceAddress); + Assert.ThrowsAsync( + async () => await client.PublishCardAsync( + GenerateRawSignedModel(faker.Random.AlphaNumeric(15)), + jwt.ToString()) + ); + } + + private Jwt JwtSignedByWrongApiKey(string identity) + { + var crypto = new VirgilCrypto(); + var wrongApiKeyPair = crypto.GenerateKeys(); + var wrongApiPublicKeyId = faker.AppId(); + return GenerateJwt(identity, wrongApiKeyPair.PrivateKey, wrongApiPublicKeyId); + } + + private Jwt GenerateJwt(string identity, PrivateKey apiPrivateKey, string apiPublicKeyId) + { + var jwtGenerator = new JwtGenerator( + AppSettings.AppId, + apiPrivateKey, + apiPublicKeyId, + TimeSpan.FromMinutes(10), + Substitute.For()); + + var jwt = jwtGenerator.GenerateToken(identity); + return jwt; + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/CryptoCompatibilityTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/CryptoCompatibilityTests.cs new file mode 100644 index 00000000..4011c658 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/CryptoCompatibilityTests.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using NUnit.Framework; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests.Shared +{ + public class CryptoCompatibilityTests + { + private readonly Dictionary> compatibilityData = + JsonConvert.DeserializeObject>>(AppSettings.CryptoCompatibilityData); + private readonly VirgilCrypto cryptoSHA256 = new VirgilCrypto() { UseSHA256Fingerprints = true }; + + [Test] + public void Decrypt_Should_BeEqualToTestData() + { + var testData = compatibilityData["encrypt_single_recipient"]; + var bytes = Bytes.FromString(testData["private_key"], StringEncoding.BASE64); + var privateKey = cryptoSHA256.ImportPrivateKey(bytes); + var publicKey = cryptoSHA256.ExtractPublicKey(privateKey); + var data = Bytes.FromString(testData["original_data"], StringEncoding.BASE64); + var cipherData = Bytes.FromString(testData["cipher_data"], StringEncoding.BASE64); + Assert.AreEqual(cryptoSHA256.Decrypt(cipherData, privateKey), (byte[])data); + } + + [Test] + public void DecryptThenVerify_Should_BeEqualToTestData() + { + var crypto = new VirgilCrypto() { UseSHA256Fingerprints = true }; + var testData = compatibilityData["sign_then_encrypt_single_recipient"]; + var privateKey = crypto.ImportPrivateKey(Bytes.FromString(testData["private_key"], StringEncoding.BASE64)); + var publicKey = crypto.ExtractPublicKey(privateKey); + var data = Bytes.FromString(testData["original_data"], StringEncoding.BASE64); + var cipherData = Bytes.FromString(testData["cipher_data"], StringEncoding.BASE64); + Assert.AreEqual(crypto.DecryptThenVerify(cipherData, privateKey, publicKey), data); + } + + [Test] + public void DecryptForMultipleRecipients_Should_BeEqualToTestData() + { + var testData = compatibilityData["encrypt_multiple_recipients"]; + var privateKeysBase64 = testData["private_keys"].ToObject(); + var privateKeys = ((string[])privateKeysBase64).Select(x => + cryptoSHA256.ImportPrivateKey(Bytes.FromString((string)x, StringEncoding.BASE64))); + var data = Bytes.FromString((string)testData["original_data"], StringEncoding.BASE64); + var cipherData = Bytes.FromString((string)testData["cipher_data"], StringEncoding.BASE64); + foreach (var privateKey in privateKeys) + { + Assert.IsTrue(cryptoSHA256.Decrypt(cipherData, privateKey).SequenceEqual(data)); + } + } + + [Test] + public void DecryptThenVerifyForMultipleRecipients_Should_BeEqualToTestData() + { + var testData = compatibilityData["sign_then_encrypt_multiple_recipients"]; + var privateKeysBase64 = testData["private_keys"].ToObject(); + + var privateKeys = ((string[])privateKeysBase64).Select(x => + cryptoSHA256.ImportPrivateKey(Bytes.FromString(x, StringEncoding.BASE64))); + var publicKeys = privateKeys.Select(x => cryptoSHA256.ExtractPublicKey(x)).ToArray(); + var signerPublicKey = publicKeys.First(); + var data = Bytes.FromString((string)testData["original_data"], StringEncoding.BASE64); + var cipherData = Bytes.FromString((string)testData["cipher_data"], StringEncoding.BASE64); + foreach (var privateKey in privateKeys) + { + Assert.IsTrue(cryptoSHA256.DecryptThenVerify(cipherData, privateKey, signerPublicKey).SequenceEqual(data)); + } + } + + [Test] + public void DecryptThenVerifytForMultipleSigners_Should_BeEqualToTestData() + { + var testData = compatibilityData["sign_then_encrypt_multiple_signers"]; + var privateKey = cryptoSHA256.ImportPrivateKey( + Bytes.FromString((string)testData["private_key"], StringEncoding.BASE64)); + + var publicKeysBase64 = testData["public_keys"].ToObject(); + var publicKeys = ((string[])publicKeysBase64).Select(x => + cryptoSHA256.ImportPublicKey(Bytes.FromString(x, StringEncoding.BASE64))).ToArray(); + var data = Bytes.FromString((string)testData["original_data"], StringEncoding.BASE64); + var cipherData = Bytes.FromString((string)testData["cipher_data"], StringEncoding.BASE64); + Assert.IsTrue(cryptoSHA256.DecryptThenVerify(cipherData, privateKey, publicKeys).SequenceEqual(data)); + } + + [Test] + public void VerifySignature_Should_BeTrueForTestData() + { + var testData = compatibilityData["generate_signature"]; + var privateKey = cryptoSHA256.ImportPrivateKey(Bytes.FromString(testData["private_key"], StringEncoding.BASE64)); + var publicKey = cryptoSHA256.ExtractPublicKey(privateKey); + var data = Bytes.FromString(testData["original_data"], StringEncoding.BASE64); + var signature = Bytes.FromString(testData["signature"], StringEncoding.BASE64); + Assert.IsTrue(cryptoSHA256.VerifySignature(signature, data, publicKey)); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/ExtendedValidatorTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/ExtendedValidatorTests.cs new file mode 100644 index 00000000..bf4d2577 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/ExtendedValidatorTests.cs @@ -0,0 +1,346 @@ +using System; +using System.Configuration; +using NSubstitute; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; +using Virgil.SDK.Verification; +using Virgil.SDK.Web; + +namespace Virgil.SDK.Tests +{ + using System.Collections.Generic; + using Bogus; + using NUnit.Framework; + using Virgil.CryptoAPI; + using Virgil.CryptoImpl; + + [TestFixture] + public class ExtendedValidatorTests + { + private readonly Faker faker = new Faker(); + + + [Test] + public void Validate_ShouldIgnoreSelfSignature_IfPropertyDoesntSetToTrue() + { + var crypto = Substitute.For(); + var validator = new VirgilCardVerifier(crypto); + var card = this.faker.Card(false); + validator.VerifyVirgilSignature = true; + validator.VerifySelfSignature = false; + crypto.VerifySignature( + card.Signatures[0].Signature, + card.ContentSnapshot, + Arg.Any()).Returns(true); + var result = validator.VerifyCard(card); + Assert.IsTrue(result); + } + + [Test] + public void Validate_ShouldIgnoreVirgilSignature_IfPropertyDoesntSetToTrue() + { + var crypto = Substitute.For(); + var validator = new VirgilCardVerifier(crypto); + var card = this.faker.Card(true, false); + validator.VerifySelfSignature = true; + validator.VerifyVirgilSignature = false; + crypto.VerifySignature( + card.Signatures[0].Signature, + card.ContentSnapshot, + card.PublicKey).Returns(true); + var result = validator.VerifyCard(card); + Assert.IsTrue(result); + } + + [Test] + public void Validate_ShouldNotValidateSelfAndVirgilSignatures_IfBothPropertiesDoesntSetToTrue() + { + var crypto = Substitute.For(); + var validator = new VirgilCardVerifier(crypto); + validator.VerifySelfSignature = false; + validator.VerifyVirgilSignature = false; + var card = this.faker.Card(); + crypto.VerifySignature(card.Signatures[0].Signature, + card.ContentSnapshot, + card.PublicKey).Returns(false); + crypto.VerifySignature( + card.Signatures[1].Signature, + card.ContentSnapshot, + Arg.Any()).Returns(false); + + var result = validator.VerifyCard(card); + Assert.IsTrue(result); + } + + [Test] + public void Validate_ShouldReturnSuccess_IfSpecifiedWhitelistSignersAreValid() + { + var crypto = Substitute.For(); + var validator = new VirgilCardVerifier(crypto); + validator.VerifySelfSignature = false; + validator.VerifyVirgilSignature = false; + var signer = this.faker.VerifierCredentialAndSignature("exta"); + var signerInfo = signer.Item1; + var signerSignature = new CardSignature() + { + Snapshot = signer.Item2.Snapshot, + Signer = signer.Item2.Signer, + Signature = signer.Item2.Signature + }; + //C signer.Item2;} + var card = this.faker.Card(false, false, new List { signerSignature }); + crypto.VerifySignature( + signerSignature.Signature, + card.ContentSnapshot, + Arg.Any()).Returns(true); + + var whiteList = new Whitelist + { + VerifiersCredentials = new List() { { signerInfo } } + }; + validator.Whitelists = new List() { whiteList }; + var result = validator.VerifyCard(card); + Assert.IsTrue(result); + } + + [Test] + public void Validate_Should_ValidateByAppSign() + { + var crypto = new VirgilCrypto(); + var validator = new VirgilCardVerifier(new VirgilCardCrypto()); + var vrigilPublicKeyBytes = crypto.ExportPublicKey(faker.PredefinedVirgilKeyPair().PublicKey); + validator.ChangeServiceCreds( + Bytes.ToString(vrigilPublicKeyBytes, StringEncoding.BASE64) + ); + + var appKeyPair = crypto.GenerateKeys(); + + var appPublicKey = Bytes.ToString(crypto.ExportPublicKey(crypto.ExtractPublicKey(appKeyPair.PrivateKey)), + StringEncoding.BASE64); + + var list = new List + { + new VerifierCredentials() + { + Signer = "my_app", PublicKeyBase64 = appPublicKey + } + }; + + //validator.Whitelist = list; + var keypair = crypto.GenerateKeys(); + var cardCrypto = new VirgilCardCrypto(); + /* var csr = CSR.Generate(cardCrypto, new CardParams + { + Identity = "some_identity", + PublicKey = crypto.ExtractPublicKey(keypair.PrivateKey), + PrivateKey = keypair.PrivateKey + }); + + + csr.Sign(cardCrypto, new ExtendedSignParams + { + SignerId = "", + SignerType = SignerType.App.ToLowerString(), + SignerPrivateKey = appKeyPair.PrivateKey + }); + + var card = CardUtils.Parse(cardCrypto, csr.RawSignedModel); + + var result = validator.VerifyCard(card); + result.Should().BeTrue();*/ + } + + + [Test] + public void EmptyVerifier_Should_VerifyCard() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, false); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = false, + VerifyVirgilSignature = false + }; + Assert.IsTrue(verifier.VerifyCard(card)); + } + + [Test] + public void Verifier_Should_VerifyCard_IfCardHasAtLeastOneSignatureFromWhitelist() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, false); + var signer = new ModelSigner(new VirgilCardCrypto()); + var crypto = new VirgilCrypto(); + var keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "extra" + }); + var creds = new VerifierCredentials(){ + PublicKeyBase64 = Bytes.ToString(crypto.ExportPublicKey(keyPair.PublicKey), + StringEncoding.BASE64), Signer = "extra" + }; + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = true, + VerifyVirgilSignature = true, + }; + var vrigilPublicKeyBytes = new VirgilCrypto().ExportPublicKey(faker.PredefinedVirgilKeyPair().PublicKey); + verifier.ChangeServiceCreds( + Bytes.ToString(vrigilPublicKeyBytes, StringEncoding.BASE64) + ); + + var whiteList = new Whitelist() + { + VerifiersCredentials = new List() + { + creds, + faker.VerifierCredentialAndSignature("extra").Item1 + } + }; + verifier.Whitelists = new List(){whiteList}; + Assert.IsTrue(verifier.VerifyCard(card)); + + } + + [Test] + public void Verifier_ShouldNot_VerifyCard_IfCardDoesntHaveSignatureFromAtLeastOneWhitelist() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, false); + var signer = new ModelSigner(new VirgilCardCrypto()); + var crypto = new VirgilCrypto(); + var keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "extra" + }); + var creds = new VerifierCredentials() + { + PublicKeyBase64 = Bytes.ToString(crypto.ExportPublicKey(keyPair.PublicKey), + StringEncoding.BASE64), + Signer = "extra" + }; + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = true, + VerifyVirgilSignature = true, + }; + var vrigilPublicKeyBytes = new VirgilCrypto().ExportPublicKey(faker.PredefinedVirgilKeyPair().PublicKey); + verifier.ChangeServiceCreds( + Bytes.ToString(vrigilPublicKeyBytes, StringEncoding.BASE64) + ); + + var whiteList = new Whitelist() + { + VerifiersCredentials = new List() { creds } + }; + verifier.Whitelists = new List() { whiteList }; + Assert.IsTrue(verifier.VerifyCard(card)); + + var whiteList2 = new Whitelist() + { + VerifiersCredentials = new List() + { + faker.VerifierCredentialAndSignature("extra").Item1 + } + }; + verifier.Whitelists = new List() { whiteList, whiteList2 }; + Assert.IsFalse(verifier.VerifyCard(card)); + + } + + [Test] + public void Verifier_ShouldNot_VerifyCard_IfVerifierHasEmptyWhitelist() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, false); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = true, + VerifyVirgilSignature = true, + Whitelists = new List() { new Whitelist() } + }; + var vrigilPublicKeyBytes = new VirgilCrypto().ExportPublicKey(faker.PredefinedVirgilKeyPair().PublicKey); + verifier.ChangeServiceCreds( + Bytes.ToString(vrigilPublicKeyBytes, StringEncoding.BASE64) + ); + + Assert.IsFalse(verifier.VerifyCard(card)); + } + + + [Test] + public void Verifier_ShouldNot_VerifyCard_IfMissedRequiredSelfSignature() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = true, + VerifyVirgilSignature = false, + }; + + Assert.IsFalse(verifier.VerifyCard(card)); + } + + [Test] + public void Verifier_ShouldNot_VerifyCard_IfWrongVirgilSignature() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, true, false); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = false, + VerifyVirgilSignature = true, + }; + + Assert.IsFalse(verifier.VerifyCard(card)); + } + + [Test] + public void Verifier_ShouldNot_VerifyCard_IfWrongSelfSignature() + { + //STC-10 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + var signer = new ModelSigner(new VirgilCardCrypto()); + var crypto = new VirgilCrypto(); + var keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "self" + }); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromJson(rawSignedModel.ExportAsJson()); + + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) + { + VerifySelfSignature = true, + VerifyVirgilSignature = false, + }; + + Assert.IsFalse(verifier.VerifyCard(card)); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/FakerExtensions.cs b/SDK/Source/Virgil.SDK.Tests.Shared/FakerExtensions.cs new file mode 100644 index 00000000..215c504d --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/FakerExtensions.cs @@ -0,0 +1,235 @@ +using System.Linq; +using System.Threading.Tasks; +using NSubstitute; +using Virgil.SDK.Signer; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests +{ + using System; + using System.Collections.Generic; + using Bogus; + using Virgil.SDK.Common; + using Verification; + using Virgil.SDK.Web; + using Virgil.CryptoAPI; + using System.Configuration; + using Virgil.CryptoImpl; + + public static class FakerExtensions + { + + public static KeyPair PredefinedKeyPair(this Faker faker) + { + var crypto = new VirgilCrypto(); + + var privateKey = + crypto.ImportPrivateKey(Bytes.FromString(AppSettings.PredefinedPrivateKeyBase64, StringEncoding.BASE64)); + var publicKey = crypto.ExtractPublicKey(privateKey); + return new KeyPair((PublicKey)publicKey, (PrivateKey)privateKey); + } + + public static KeyPair PredefinedVirgilKeyPair(this Faker faker) + { + var crypto = new VirgilCrypto(); + var privateKey = + crypto.ImportPrivateKey(Bytes.FromString(AppSettings.PredefinedPrivateKeyBase64, StringEncoding.BASE64)); + var publicKey = crypto.ExtractPublicKey(privateKey); + return new KeyPair((PublicKey)publicKey, (PrivateKey)privateKey); + } + public static Card Card(this Faker faker, + bool addSelfSignature = true, + bool addVirgilSignature = true, + List signatures = null) + { + + var fingerprint = faker.Random.Bytes(32); + var cardId = Bytes.ToString(fingerprint, StringEncoding.HEX); + + if (signatures == null) + { + signatures = new List(); + } + + if (addSelfSignature) + { + signatures.Add(new CardSignature + { + Signer = ModelSigner.SelfSigner, + Signature = faker.Random.Bytes(64) + }); + } + + if (addVirgilSignature) + { + signatures.Add(new CardSignature { + Signature = faker.Random.Bytes(64), + Signer = ModelSigner.VirgilSigner + + }); + } + var crypto = new VirgilCrypto(); + + var somePublicKey = crypto.GenerateKeys().PublicKey; + + var card = new Card + ( + cardId, + faker.Person.UserName, + somePublicKey, + //faker.Random.ArrayElement(new[] {"4.0", "5.0"}), + "5.0", + faker.Date.Between(DateTime.MinValue, DateTime.MaxValue), + signatures, + null, //todo snapshot faker + null + ); + + return card; + } + + public static string CardId(this Faker faker) + { + var fingerprint = faker.Random.Bytes(32); + var cardId = Bytes.ToString(fingerprint, StringEncoding.HEX); + + return cardId; + } + + + + public static string AppId(this Faker faker) + { + var appId = Bytes.ToString(faker.Random.Bytes(32), StringEncoding.HEX); + + return appId; + } + + + public static Tuple VerifierCredentialAndSignature(this Faker faker, string signer) + { + var crypto = new VirgilCrypto(); + var keypair = crypto.GenerateKeys(); + return new Tuple( + new VerifierCredentials { Signer = signer, + PublicKeyBase64 = Bytes.ToString(crypto.ExportPublicKey(keypair.PublicKey), StringEncoding.BASE64) }, + new RawSignature() { Signer = signer, Signature = faker.Random.Bytes(64) }); + } + + public static CardSignature CardSignature(this Faker faker) + { + return new CardSignature { Signer = "extra", Signature = faker.Random.Bytes(64) }; + } + + + public static RawSignedModel PredefinedRawSignedModel(this Faker faker, + string previousCardId = null, + bool addSelfSignature = false, + bool addVirgilSignature = false, + bool addExtraSignature = false + ) + { + var crypto = new VirgilCrypto(); + var keyPair = faker.PredefinedKeyPair(); + var dateTime = DateTimeOffset.FromUnixTimeSeconds(Int64.Parse("1515686245")).DateTime; + var rawCardContent = new RawCardContent() + { + CreatedAt = dateTime, + Identity = "test", + PublicKey = crypto.ExportPublicKey(keyPair.PublicKey), + Version = "5.0", + PreviousCardId = previousCardId + }; + var model = new RawSignedModel() { ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent) }; + + var signer = new ModelSigner(new VirgilCardCrypto()); + if (addSelfSignature) + { + signer.SelfSign(model, keyPair.PrivateKey); + } + + if (addVirgilSignature) + { + signer.Sign(model, new SignParams() + { + Signer = ModelSigner.VirgilSigner, + SignerPrivateKey = faker.PredefinedVirgilKeyPair().PrivateKey + }); + } + + if (addExtraSignature) + { + signer.Sign(model, new SignParams() + { + Signer = "extra", + SignerPrivateKey = crypto.GenerateKeys().PrivateKey + }); + } + return model; + } + + public static RawSignedModel RawCard(this Faker faker) + { + var rawCardContent = Substitute.For(); + return new RawSignedModel() {ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent)}; + } + + public static CardManager CardManager( + this Faker faker, + IAccessTokenProvider tokenProvider, + bool retryOnUnauthorized = false) + { + //Func> signCallBackFunc = Substitute.For< + // Func>>(); + var verifier = new VirgilCardVerifier(new VirgilCardCrypto()) {VerifySelfSignature = false, VerifyVirgilSignature = false}; + + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = new VirgilCardCrypto(), + AccessTokenProvider = tokenProvider, + SignCallBack = null, + Verifier = verifier, + ApiUrl = AppSettings.CardsServiceAddress, + RetryOnUnauthorized = retryOnUnauthorized + }); + return manager; + } + + public static CardManager CardManager(this Faker faker) + { + return faker.CardManager(Substitute.For()); + } + + public static Tuple PredefinedToken( + this Faker faker, + VirgilAccessTokenSigner signer, + TimeSpan lifeTime, + out string apiPublicKeyId, + out string apiPublicKeyBase64) + { + var crypto = new VirgilCrypto(); + var apiKeyPair = crypto.GenerateKeys(); + var fingerprint = crypto.GenerateHash(crypto.ExportPublicKey(apiKeyPair.PublicKey)); + apiPublicKeyId = Bytes.ToString(fingerprint, StringEncoding.HEX); + + apiPublicKeyBase64 = Bytes.ToString( + crypto.ExportPublicKey(apiKeyPair.PublicKey), StringEncoding.BASE64); + + var jwtGenerator = new JwtGenerator( + faker.AppId(), + apiKeyPair.PrivateKey, + apiPublicKeyId, + lifeTime, + signer); + + var additionalData = new Dictionary + { + {"username", "some_username"} + }; + var dict = additionalData.ToDictionary(entry => (object)entry.Key, entry => (object)entry.Value); + var token = jwtGenerator.GenerateToken("some_identity", dict); + return new Tuple(token, jwtGenerator); + } + + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/IntegrationHelper.cs b/SDK/Source/Virgil.SDK.Tests.Shared/IntegrationHelper.cs new file mode 100644 index 00000000..4828ddc7 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/IntegrationHelper.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Virgil.CryptoAPI; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; +using Virgil.SDK.Verification; +using Virgil.SDK.Web; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests +{ + public class IntegrationHelper + { + public static VirgilCardCrypto CardCrypto = new VirgilCardCrypto(); + public static VirgilCrypto Crypto = new VirgilCrypto(); + + public static IPrivateKey ApiPrivateKey() + { + return Crypto.ImportPrivateKey( + Bytes.FromString(AppSettings.ApiPrivateKeyBase64, StringEncoding.BASE64)); + } + + public static CardManager GetManager() + { + Func> obtainToken = async (TokenContext tokenContext) => + { + var jwtFromServer = await EmulateServerResponseToBuildTokenRequest(tokenContext); + + return jwtFromServer; + }; + + + Func> signCallBackFunc = async (model) => + { + var response = await EmulateServerResponseToSignByAppRequest(model.ExportAsString()); + return RawSignedModelUtils.GenerateFromString(response); + }; + + var validator = new VirgilCardVerifier(new VirgilCardCrypto()) { VerifySelfSignature = true, VerifyVirgilSignature = true}; + validator.ChangeServiceCreds(AppSettings.ServicePublicKeyDerBase64); + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = CardCrypto, + ApiUrl = AppSettings.CardsServiceAddress, + AccessTokenProvider = new CallbackJwtProvider(obtainToken), + SignCallBack = signCallBackFunc, + Verifier = validator + }); + return manager; + } + + public static Task EmulateServerResponseToBuildTokenRequest(TokenContext tokenContext) + { + var serverResponse = Task.Factory.StartNew(() => + { + Thread.Sleep(1000); // simulation of long-term processing + var data = new Dictionary + { + {"username", "my_username"} + }; + var builder = new JwtGenerator( + AppSettings.AppId, + ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.FromMinutes(10), + new VirgilAccessTokenSigner() + ); + var identity = SomeHash(tokenContext.Identity); + return builder.GenerateToken(identity, data).ToString(); + } + ); + + return serverResponse; + } + private static Task EmulateServerResponseToSignByAppRequest(string modelStr) + { + var serverResponse = Task.Factory.StartNew(() => + { + Thread.Sleep(1000); // simulation of long-term processing + // var appPrivateKey = Crypto.ImportVirgilPrivateKey( + // Bytes.FromString(AccessPublicKeyId, StringEncoding.BASE64)); + var rawSignedModel = RawSignedModelUtils.GenerateFromString(modelStr); + + return rawSignedModel.ExportAsString(); + }); + return serverResponse; + } + + private static string SomeHash(string identity) + { + return String.IsNullOrWhiteSpace(identity) ? "my_default_identity" : identity; + } + public static async Task PublishCard(string username, string previousCardId = null) + { + var keypair = Crypto.GenerateKeys(); + return await GetManager().PublishCardAsync( + new CardParams() + { + Identity = username, + PublicKey = keypair.PublicKey, + PrivateKey = keypair.PrivateKey, + PreviousCardId = previousCardId, + ExtraFields = new Dictionary + { + { "some meta key", "some meta val" } + } + }); + } + + public static async Task GetCard(string cardId) + { + return await GetManager().GetCardAsync(cardId); + } + + internal static Task> SearchCardsAsync(string identity) + { + return GetManager().SearchCardsAsync(identity); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/JwtVerifierTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/JwtVerifierTests.cs new file mode 100644 index 00000000..3c124b7b --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/JwtVerifierTests.cs @@ -0,0 +1,50 @@ +using System; +using Bogus; +using NUnit.Framework; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests.Shared +{ + [NUnit.Framework.TestFixture] + public class JwtVerifierTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void JwtVerifier_Should_VerifyImportedJwt() + { + //STC-22 + var signer = new VirgilAccessTokenSigner(); + string apiPublicKeyId; + string apiPublicKeyBase64; + var crypto = new VirgilCrypto(); + + var token = faker.PredefinedToken(signer, TimeSpan.FromMinutes(10), out apiPublicKeyId, out apiPublicKeyBase64).Item1; + + var jwtVerifier = new JwtVerifier( + signer, + crypto.ImportPublicKey(Bytes.FromString(apiPublicKeyBase64, StringEncoding.BASE64)), + apiPublicKeyId); + + Assert.IsTrue(jwtVerifier.VerifyToken(token)); + } + + [Test] + public void Verify_Should_VerifyTestCreatedInAnotherSDK() + { + var jwt = new Jwt(AppSettings.ImportedJwt); + var signer = new VirgilAccessTokenSigner(); + var crypto = new VirgilCrypto(); + + var jwtVerifier = new JwtVerifier( + signer, + crypto.ImportPublicKey( + Bytes.FromString(AppSettings.ImportedAccessPublicKey, StringEncoding.BASE64)), + AppSettings.ImportedAccessPublicKeyId); + + Assert.IsTrue(jwtVerifier.VerifyToken(jwt)); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/ModelSignerTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/ModelSignerTests.cs new file mode 100644 index 00000000..54b02744 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/ModelSignerTests.cs @@ -0,0 +1,158 @@ +using System.Linq; +using Bogus; +using NUnit.Framework; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; + +namespace Virgil.SDK.Tests.Shared +{ + [NUnit.Framework.TestFixture] + public class ModelSignerTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void SelfSign_Should_AddValidSignature() + { + //STC-8 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + var crypto = new VirgilCrypto(); + var signer = new ModelSigner(new VirgilCardCrypto()); + Assert.AreEqual(rawSignedModel.Signatures.Count, 0); + + signer.SelfSign(rawSignedModel, faker.PredefinedKeyPair().PrivateKey); + Assert.AreEqual(rawSignedModel.Signatures.Count, 1); + var selfSignature = rawSignedModel.Signatures.First(); + var cardId = CardUtils.GenerateCardId(new VirgilCardCrypto(), rawSignedModel.ContentSnapshot); + Assert.AreEqual(selfSignature.Signer, ModelSigner.SelfSigner); + Assert.AreEqual(selfSignature.Snapshot, null); + Assert.True(crypto.VerifySignature( + selfSignature.Signature, + rawSignedModel.ContentSnapshot, + faker.PredefinedKeyPair().PublicKey) + ); + } + + [Test] + public void SelfSignWithSignatureSnapshot_Should_AddValidSignature() + { + //STC-9 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + var crypto = new VirgilCrypto(); + var signer = new ModelSigner(new VirgilCardCrypto()); + Assert.AreEqual(rawSignedModel.Signatures.Count, 0); + var signatureSnapshot = faker.Random.Bytes(32); + signer.SelfSign(rawSignedModel, faker.PredefinedKeyPair().PrivateKey, signatureSnapshot); + var selfSignature = rawSignedModel.Signatures.First(); + Assert.AreEqual(selfSignature.Signer, ModelSigner.SelfSigner); + Assert.AreEqual(selfSignature.Snapshot, signatureSnapshot); + + var extendedSnapshot = Bytes.Combine(rawSignedModel.ContentSnapshot, signatureSnapshot); + + Assert.True(crypto.VerifySignature( + selfSignature.Signature, + extendedSnapshot, + faker.PredefinedKeyPair().PublicKey) + ); + } + + [Test] + public void SecondSelfSign_Should_ThrowException() + { + //STC-8 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, false, false); + var crypto = new VirgilCrypto(); + var keyPair = crypto.GenerateKeys(); + var signer = new ModelSigner(new VirgilCardCrypto()); + + Assert.Throws( + () => signer.SelfSign(rawSignedModel, keyPair.PrivateKey) + ); + } + + + [Test] + public void ExtraSign_Should_AddValidSignature() + { + //STC-8 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, false, false); + var crypto = new VirgilCrypto(); + var signer = new ModelSigner(new VirgilCardCrypto()); + + Assert.AreEqual(rawSignedModel.Signatures.Count, 1); + var keyPair = crypto.GenerateKeys(); + var signParams = new SignParams() + { + Signer = "test_id", + SignerPrivateKey = keyPair.PrivateKey + }; + signer.Sign(rawSignedModel, signParams + ); + Assert.AreEqual(rawSignedModel.Signatures.Count, 2); + var extraSignature = rawSignedModel.Signatures.Last(); + Assert.AreEqual(extraSignature.Signer, signParams.Signer); + Assert.AreEqual(extraSignature.Snapshot, null); + Assert.True(crypto.VerifySignature( + extraSignature.Signature, + rawSignedModel.ContentSnapshot, + keyPair.PublicKey)); + } + + [Test] + public void ExtraSignWithSignatureSnapshot_Should_AddValidSignature() + { + //STC-9 + var rawSignedModel = faker.PredefinedRawSignedModel(null, true, false, false); + var crypto = new VirgilCrypto(); + var signer = new ModelSigner(new VirgilCardCrypto()); + + Assert.AreEqual(rawSignedModel.Signatures.Count, 1); + var keyPair = crypto.GenerateKeys(); + var signParams = new SignParams() + { + Signer = "test_id", + SignerPrivateKey = keyPair.PrivateKey + }; + var signatureSnapshot = faker.Random.Bytes(32); + + signer.Sign(rawSignedModel, signParams, signatureSnapshot); + Assert.AreEqual(rawSignedModel.Signatures.Count, 2); + var extraSignature = rawSignedModel.Signatures.Last(); + Assert.AreEqual(extraSignature.Signer, signParams.Signer); + Assert.AreEqual(extraSignature.Snapshot, signatureSnapshot); + + var extendedSnapshot = Bytes.Combine(rawSignedModel.ContentSnapshot, signatureSnapshot); + Assert.True(crypto.VerifySignature( + extraSignature.Signature, + extendedSnapshot, + keyPair.PublicKey)); + } + + [Test] + public void SecondExtraSign_Should_ThrowException() + { + //STC-8 + var rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + var crypto = new VirgilCrypto(); + var signer = new ModelSigner(new VirgilCardCrypto()); + + var keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, + new SignParams() + { + Signer = "test_id", + SignerPrivateKey = keyPair.PrivateKey + }); + + Assert.Throws( + () => signer.Sign(rawSignedModel, + new SignParams() + { + Signer = "test_id", + SignerPrivateKey = keyPair.PrivateKey + }) + ); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/MyClass.cs b/SDK/Source/Virgil.SDK.Tests.Shared/MyClass.cs new file mode 100644 index 00000000..e9326808 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/MyClass.cs @@ -0,0 +1,10 @@ +using System; +namespace Virgil.SDK.Tests.Shared +{ + public class MyClass + { + public MyClass() + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/PetaJsonSerializerTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/PetaJsonSerializerTests.cs new file mode 100644 index 00000000..f65564a5 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/PetaJsonSerializerTests.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Linq; +using Virgil.SDK.Common; +using Virgil.SDK.Web; + + +namespace Virgil.SDK.Tests +{ + using Bogus; + using NUnit.Framework; + + [TestFixture] + public class PetaJsonSerializerTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void Serialize_Should_ConvertByteArrayToBase64String() + { + var rawCard = faker.RawCard(); + var serializer = new PetaJsonSerializer(); + var serializedRawCard = serializer.Serialize(rawCard); + var snapshotBase64 = Bytes.ToString(rawCard.ContentSnapshot, StringEncoding.BASE64); + + Assert.IsTrue(serializedRawCard.Contains(snapshotBase64)); + } + + + [Test] + public void Serialize_Should_ConvertDictionary() + { + var dict = new Dictionary(); + dict.Add("username", "anna"); + dict.Add("passw", "mypassword"); + var serializer = new PetaJsonSerializer(); + var serializedDict = serializer.Serialize(dict); + Assert.AreEqual(dict, serializer.Deserialize>(serializedDict)); + + } + + [Test] + public void Deserialize_Should_ConvertBase64StringToByteArray() + { + const string cardRawJson = "{ \"id\": \"12345\", \"content_snapshot\":\"AQIDBAU=\" }"; + var serializer = new PetaJsonSerializer(); + var cardRaw = serializer.Deserialize(cardRawJson); + + Assert.AreEqual(cardRaw.ContentSnapshot, Bytes.FromString("AQIDBAU=", StringEncoding.BASE64)); + } + + + [Test] + public void Deserialize_Should_EquivalentToOrigin() + { + var rawCard = faker.PredefinedRawSignedModel(null, true); + var serializer = new PetaJsonSerializer(); + var serializedRawCard = serializer.Serialize(rawCard); + var deserializeRawCard = serializer.Deserialize(serializedRawCard); + Assert.IsTrue(deserializeRawCard.ContentSnapshot.SequenceEqual(rawCard.ContentSnapshot)); + + var first = deserializeRawCard.Signatures.First(); + var sec = rawCard.Signatures.First(); + Assert.AreEqual(first.Signature, sec.Signature); + Assert.AreEqual(first.Snapshot, sec.Snapshot); + Assert.IsTrue(deserializeRawCard.ContentSnapshot.SequenceEqual(rawCard.ContentSnapshot)); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/PrivateKeyStorageTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/PrivateKeyStorageTests.cs new file mode 100644 index 00000000..ccb685d6 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/PrivateKeyStorageTests.cs @@ -0,0 +1,141 @@ +using Bogus; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using Virgil.CryptoImpl; +using Virgil.SDK.Exceptions; +using Virgil.SDK.Storage; + +namespace Virgil.SDK.Tests.Shared +{ + [NUnit.Framework.TestFixture] + public class PrivateKeyStorageTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void Store_Should_StorePrivateKey() + { + var exporterPass = faker.Random.AlphaNumeric(10); + var storagePass = faker.Random.AlphaNumeric(10); + var crypto = new VirgilCrypto(); + var privateKey = crypto.GenerateKeys().PrivateKey; + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + + var alias = faker.Random.AlphaNumeric(5); + var data = new Dictionary(){ + { + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(20) + } }; + privateKeyStorage.Store(privateKey, alias, data); + var (loadedPrivateKey, loadedData) = privateKeyStorage.Load(alias); + //Assert.IsTrue(exporter.ExportPrivatekey(privateKey).SequenceEqual( + // exporter.ExportPrivatekey((PrivateKey)loadedPrivateKey))); + Assert.AreEqual(data, loadedData); + privateKeyStorage.Delete(alias); + } + + + [Test] + public void Store_Should_RaiseException_IfAliasAlreadyExist() + { + var exporterPass = faker.Random.AlphaNumeric(10); + var storagePass = faker.Random.AlphaNumeric(10); + var crypto = new VirgilCrypto(); + var privateKey = crypto.GenerateKeys().PrivateKey; + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + var alias = faker.Random.AlphaNumeric(5); + var data = new Dictionary(){ + { + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(20) + } }; + privateKeyStorage.Store(privateKey, alias, data); + Assert.Throws(() => privateKeyStorage.Store(privateKey, alias, data)); + privateKeyStorage.Delete(alias); + } + + [Test] + public void Store_Should_RaiseException_IfKeyIsAbsent() + { + var alias = faker.Random.AlphaNumeric(5); + var storagePass = faker.Random.AlphaNumeric(10); + var exporterPass = faker.Random.AlphaNumeric(10); + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + Assert.Throws( + () => privateKeyStorage.Load(alias) + ); + } + + [Test] + public void Delete_Should_RaiseException_IfKeyIsAbsent() + { + var alias = faker.Random.AlphaNumeric(5); + var storagePass = faker.Random.AlphaNumeric(10); + var exporterPass = faker.Random.AlphaNumeric(10); + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + Assert.Throws( + () => privateKeyStorage.Delete(alias) + ); + } + + [Test] + public void Delete_Should_DeleteKey() + { + var exporterPass = faker.Random.AlphaNumeric(10); + var storagePass = faker.Random.AlphaNumeric(10); + var crypto = new VirgilCrypto(); + var privateKey = crypto.GenerateKeys().PrivateKey; + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + var alias = faker.Random.AlphaNumeric(5); + var data = new Dictionary(){ + { + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(20) + } }; + privateKeyStorage.Store(privateKey, alias, data); + Assert.IsTrue(privateKeyStorage.Exists(alias)); + privateKeyStorage.Delete(alias); + Assert.IsFalse(privateKeyStorage.Exists(alias)); + } + + public void Aliases_Should_HaveAllSavedAliases() + { + var exporterPass = faker.Random.AlphaNumeric(10); + var storagePass = faker.Random.AlphaNumeric(10); + var crypto = new VirgilCrypto(); + var privateKey = crypto.GenerateKeys().PrivateKey; + var exporter = new VirgilPrivateKeyExporter(exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + var alias = faker.Random.AlphaNumeric(5); + var alias2 = faker.Random.AlphaNumeric(5); + + var data = new Dictionary(){ + { + faker.Random.AlphaNumeric(10), + faker.Random.AlphaNumeric(20) + } }; + Assert.IsTrue(privateKeyStorage.Aliases().Length == 0); + privateKeyStorage.Store(privateKey, alias, data); + privateKeyStorage.Store(privateKey, alias2, data); + + Assert.IsTrue(privateKeyStorage.Aliases().Length == 2); + Assert.IsTrue(privateKeyStorage.Aliases().Contains(alias)); + Assert.IsTrue(privateKeyStorage.Aliases().Contains(alias2)); + + privateKeyStorage.Delete(alias); + Assert.IsFalse(privateKeyStorage.Aliases().Contains(alias)); + Assert.IsTrue(privateKeyStorage.Aliases().Contains(alias2)); + privateKeyStorage.Delete(alias2); + Assert.IsTrue(privateKeyStorage.Aliases().Length == 0); + + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/RawSignedModelTests.cs b/SDK/Source/Virgil.SDK.Tests.Shared/RawSignedModelTests.cs new file mode 100644 index 00000000..d73a4a87 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/RawSignedModelTests.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Bogus; +using NUnit.Framework; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; +using Virgil.SDK.Web; + +namespace Virgil.SDK.Tests.Shared +{ + [TestFixture] + class RawSignedModelTests + { + private readonly Faker faker = new Faker(); + + [Test] + public void GeneratePureModelFromString_Should_ReturnEquivalentModel() + { + //STC-1 + var model = faker.PredefinedRawSignedModel(); + var exportedStr = model.ExportAsString(); + + var importedModel = RawSignedModelUtils.GenerateFromString(exportedStr); + Assert.IsTrue(importedModel.ContentSnapshot.SequenceEqual(model.ContentSnapshot)); + Assert.AreEqual(Configuration.Serializer.Serialize(importedModel.Signatures), + Configuration.Serializer.Serialize(model.Signatures)); + } + + [Test] + public void Export_WithEmptyPreviousCardId_ShouldNot_HavePreviousCardIdInJson() + { + var model = faker.PredefinedRawSignedModel(); + var exportedStr = model.ExportAsJson(); + + Assert.IsFalse(exportedStr.Contains("previous_card_id")); + } + + + [Test] + public void GeneratePureModelFromJson_Should_ReturnEquivalentModel() + { + //STC-1 + var model = faker.PredefinedRawSignedModel(); + var exportedJson = model.ExportAsJson(); + + var importedModel = RawSignedModelUtils.GenerateFromJson(exportedJson); + Assert.IsTrue(importedModel.ContentSnapshot.SequenceEqual(model.ContentSnapshot)); + Assert.AreEqual(Configuration.Serializer.Serialize(importedModel.Signatures), + Configuration.Serializer.Serialize(model.Signatures)); + } + + [Test] + public void GenerateFullModelFromString_Should_ReturnEquivalentModel() + { + //STC-2 + var model = faker.PredefinedRawSignedModel( + "a666318071274adb738af3f67b8c7ec29d954de2cabfd71a942e6ea38e59fff9", + true, true, true); + + var exportedStr = model.ExportAsString(); + var importedModel = RawSignedModelUtils.GenerateFromString(exportedStr); + Assert.IsTrue(importedModel.ContentSnapshot.SequenceEqual(model.ContentSnapshot)); + Assert.AreEqual(Configuration.Serializer.Serialize(importedModel.Signatures), + Configuration.Serializer.Serialize(model.Signatures)); + } + + [Test] + public void GenerateFullModelFromJson_Should_ReturnEquivalentModel() + { + //STC-2 + var model = faker.PredefinedRawSignedModel( + "a666318071274adb738af3f67b8c7ec29d954de2cabfd71a942e6ea38e59fff9", + true, true, true); + var exportedJson = model.ExportAsJson(); + var importedModel = RawSignedModelUtils.GenerateFromJson(exportedJson); + Assert.IsTrue(importedModel.ContentSnapshot.SequenceEqual(model.ContentSnapshot)); + Assert.AreEqual(Configuration.Serializer.Serialize(importedModel.Signatures), + Configuration.Serializer.Serialize(model.Signatures)); + + } + + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.projitems b/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.projitems new file mode 100644 index 00000000..bf1412f9 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.projitems @@ -0,0 +1,31 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {3D15E8EB-42FE-4756-93E1-506C28E48612} + + + Virgil.SDK.Tests.Shared + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.shproj b/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.shproj new file mode 100644 index 00000000..2bc35c4f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/Virgil.SDK.Tests.Shared.shproj @@ -0,0 +1,11 @@ + + + + {3D15E8EB-42FE-4756-93E1-506C28E48612} + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/app-sample.config b/SDK/Source/Virgil.SDK.Tests.Shared/app-sample.config new file mode 100644 index 00000000..aabfde81 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/app-sample.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/SDK/Source/Virgil.SDK.Tests.Shared/packages.config b/SDK/Source/Virgil.SDK.Tests.Shared/packages.config new file mode 100644 index 00000000..441e5829 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.Shared/packages.config @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs b/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs new file mode 100644 index 00000000..de6ad2c2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +using Foundation; +using UIKit; +using NUnit.Runner.Services; +using PCLAppConfig; +using System.IO; + +namespace Virgil.SDK.Tests.iOS +{ + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to + // application events from iOS. + [Register("AppDelegate")] + public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate + { + // + // This method is invoked when the application has loaded and is ready to run. In this + // method you should instantiate the window, load the UI into it and then make the window + // visible. + // + // You have 17 seconds to return from this method, or iOS will terminate your application. + // + public override bool FinishedLaunching(UIApplication app, NSDictionary options) + { + global::Xamarin.Forms.Forms.Init(); + + // This will load all tests within the current project + var nunit = new NUnit.Runner.App(); + + // If you want to add tests in another assembly + //nunit.AddTestAssembly(typeof(MyTests).Assembly); + ConfigurationManager.Initialise(PCLAppConfig.FileSystemStream.PortableStream.Current); + var AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + // var AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + var cryptoTestData = File.ReadAllText("TestData/crypto_compatibility_data.json"); + AppSettings.CryptoCompatibilityData = cryptoTestData; + + // Do you want to automatically run tests when the app starts? + nunit.Options = new TestOptions + { + AutoRun = true + }; + + LoadApplication(nunit); + + return base.FinishedLaunching(app, options); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs.txt b/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs.txt new file mode 100644 index 00000000..8134733d --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/AppDelegate.cs.txt @@ -0,0 +1,75 @@ +// *********************************************************************** +// Copyright (c) 2015 Charlie Poole +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// *********************************************************************** + +using Foundation; +using UIKit; + +namespace Virgil.SDK.Tests.iOS +{ + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to + // application events from iOS. + [Register("AppDelegate")] + public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate + { + // + // This method is invoked when the application has loaded and is ready to run. In this + // method you should instantiate the window, load the UI into it and then make the window + // visible. + // + // You have 17 seconds to return from this method, or iOS will terminate your application. + // + public override bool FinishedLaunching(UIApplication app, NSDictionary options) + { + global::Xamarin.Forms.Forms.Init(); + + // This will load all tests within the current project + var nunit = new NUnit.Runner.App(); + + // If you want to add tests in another assembly + //nunit.AddTestAssembly(typeof(MyTests).Assembly); + + // Available options for testing + nunit.Options = new TestOptions + { + // If True, the tests will run automatically when the app starts + // otherwise you must run them manually. + AutoRun = true, + + // If True, the application will terminate automatically after running the tests. + //TerminateAfterExecution = true, + + // Information about the tcp listener host and port. + // For now, send result as XML to the listening server. + // TcpWriterParameters = new TcpWriterInfo("192.168.0.108", 13000), + + // Creates a NUnit Xml result file on the host file system using PCLStorage library. + CreateXmlResultFile = false + }; + + LoadApplication(nunit); + + return base.FinishedLaunching(app, options); + } + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/AppSettings.cs b/SDK/Source/Virgil.SDK.Tests.iOS/AppSettings.cs new file mode 100644 index 00000000..ec6de9ea --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/AppSettings.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using PCLAppConfig; +using Virgil.SDK.Common; + +namespace Virgil.SDK.Tests +{ + public class AppSettings + { + static AppSettings(){ + } + + public static string AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + public static string AccounId = ConfigurationManager.AppSettings["virgil:AccountID"]; + public static string AppPrivateKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; + public static string ApiPublicKeyId = ConfigurationManager.AppSettings["virgil:AccessPublicKeyId"]; + public static string ApiPrivateKeyBase64 = ConfigurationManager.AppSettings["virgil:AccessPrivateKeyBase64"]; + public static string ServiceCardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"]; + public static string ServicePublicKeyPemBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyPemBase64"]; + public static string ServicePublicKeyDerBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"]; + public static string CryptoCompatibilityData = ""; + public static string OutputTestDataPath = ConfigurationManager.AppSettings["test:OutputDataPath"]; + public static string CardsServiceAddress = ConfigurationManager.AppSettings["virgil:CardsServicesAddressV5"]; + + public static string PrivateKeySTC31_1 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_1"]; + public static string PrivateKeySTC31_2 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_2"]; + public static string PublicKeySTC32 = ConfigurationManager.AppSettings["test:PublicKeySTC32"]; + + public static string ImportedAccessPublicKeyId = ConfigurationManager.AppSettings["test:ImportedAccessPublicKeyId"]; + public static string ImportedAccessPublicKey = ConfigurationManager.AppSettings["test:ImportedAccessPublicKey"]; + + public static string PredefinedPrivateKeyBase64 = ConfigurationManager.AppSettings["test:PredefinedPrivateKeyBase64"]; + + public static string ImportedJwt = ConfigurationManager.AppSettings["test:ImportedJwt"]; + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/Entitlements.plist b/SDK/Source/Virgil.SDK.Tests.iOS/Entitlements.plist new file mode 100644 index 00000000..9ae59937 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/Info.plist b/SDK/Source/Virgil.SDK.Tests.iOS/Info.plist new file mode 100644 index 00000000..1b2c94e1 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleIdentifier + com.virgil11 + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 7.0 + UIDeviceFamily + + 1 + 2 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UILaunchStoryboardName + LaunchScreen + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + CFBundleName + Virgil.SDK.Tests.iOS + + diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/LaunchScreen.storyboard b/SDK/Source/Virgil.SDK.Tests.iOS/LaunchScreen.storyboard new file mode 100644 index 00000000..7981a14b --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/Main.cs b/SDK/Source/Virgil.SDK.Tests.iOS/Main.cs new file mode 100644 index 00000000..29b3ba80 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/Main.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +using Foundation; +using UIKit; + +namespace Virgil.SDK.Tests.iOS +{ + public class Application + { + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "UnitTestAppDelegate" + // you can specify it here. + UIApplication.Main(args, null, "AppDelegate"); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/SecureStorageTests.cs b/SDK/Source/Virgil.SDK.Tests.iOS/SecureStorageTests.cs new file mode 100644 index 00000000..ee9f389b --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/SecureStorageTests.cs @@ -0,0 +1,102 @@ +using System; +using Bogus; +using NUnit.Framework; +using Virgil.SDK; +using Virgil.SDK.Storage; +using Virgil.SDK.Storage.Exceptions; + +namespace AndroidTestApp +{ + + [TestFixture] + public class SecureStorageTests + { + private readonly Faker faker = new Faker(); + + [SetUp] + public void SetUp() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Test"; + } + + [Test] + public void Save_Should_SaveDataUnderKey() + { + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storedData = storage.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void Save_Should_SaveDataBetweenSessions() + { + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storage2 = new SecureStorage(); + + var storedData = storage2.Load(key); + Assert.AreEqual(storedData, data); + storage.Delete(key); + } + + [Test] + public void SaveWithDuplicateKey_Should_RaiseDuplicateKeyException() + { + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + Assert.Throws( + () => storage.Save(key, data)); + storage.Delete(key); + } + + [Test] + public void LoadByMissingKey_Should_RaiseKeyNotFoundException() + { + var storage = new SecureStorage(); + var key = faker.Person.UserName; + + Assert.Throws( + () => storage.Load(key)); + } + + [Test] + public void DeleteByMissingKey_Should_RaiseKeyNotFoundException() + { + var storage = new SecureStorage(); + var key = faker.Person.UserName; + Assert.Throws( + () => storage.Delete(key)); + } + + [Test] + public void Keys_Should_ReturnAllSavedKeys() + { + var storage = new SecureStorage(); + var data = faker.Random.Bytes(32); + var key = "my_key_1"; + var key2 = "my_key_2"; + + storage.Save(key, data); + storage.Save(key2, data); + var keys = storage.Aliases(); + Assert.AreNotEqual(Array.IndexOf(keys, key), -1); + Assert.AreNotEqual(Array.IndexOf(keys, key2), -1); + + storage.Delete(key); + storage.Delete(key2); + } + + } + +} diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/Testdata/crypto_compatibility_data.json b/SDK/Source/Virgil.SDK.Tests.iOS/Testdata/crypto_compatibility_data.json new file mode 100644 index 00000000..d3d9385f --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/Testdata/crypto_compatibility_data.json @@ -0,0 +1,54 @@ +{ + "encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIFx8vNiUAME3rwAoVMyuZg/F14FcMF5WETOeEV3Zr8c7", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIBYgIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQg9b1JYQ61xgfxYN1lFZkPOlB7XDMd/rxcVk8r2MPGntMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB066Ul4v6X9zUXoHx8TxlgaQC8c6ayVchkItZDfRZGwTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMGtLjjW6Rl3JMCh5683PT5E1LDdaspCLUnBJjWarkRnbcrmMt8yqLle6H4QVeqvIhjBRMB0GCWCGSAFlAwQBKgQQrP3B71mD165GE5vhEomT7QQwy25y+b+4DEHPp1RLHatp7uJ4ZwXMrsawrj/TOlCmz0oGz91v19McaA+r1wIMCnukMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDDGYn3cJsIhBAHq4F4sC+6JJBMT3Jh3GcrDp/F7E0LPRVHEXf9GzfvlW3SOzfG56CsLOmjIdZoqQgne8VLHWUYMXQKDae3s3AQBuo7d7EytYtUAgdw==" + }, + "encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIKyyfp+ssJL6AkwndBWL6jOPgswH+BVDzxU8md6nA40t", + "MC4CAQAwBQYDK2VwBCIEIAFYY8PG8enCO6NdUv1UVnC65ryr2mrGV6QDlJEliv3y", + "MC4CAQAwBQYDK2VwBCIEIATkmvo7jh0syRtTg1mNfSJNvqB1V9/bEKijP+rmK5MO", + "MC4CAQAwBQYDK2VwBCIEIK7KLGRPADz3NKk4p0hq3q/wwqN5g08pzN0b9+0NbgXq", + "MC4CAQAwBQYDK2VwBCIEIOJIlOdeAygksA2Y4RHJBQ51emPtVW257jeWiwMnS3nQ", + "MC4CAQAwBQYDK2VwBCIEIPVooGKp/JArB4dD5LDDjHeIsbBkAfDfWNgzFoAYov1C", + "MC4CAQAwBQYDK2VwBCIEIFEaV3yA+7ui8SgHLVzjCY/ZLfc5m8FMHe6nzlV/fOk3", + "MC4CAQAwBQYDK2VwBCIEIHLc4yhkFXMceatKElNvmgIsixBc0KkRxEL/FmnhzJTx" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIJEQIBADCCCQoGCSqGSIb3DQEHA6CCCPswggj3AgECMYIIyDCCARUCAQKgIgQgAz7ucGlal9Ci/bo+cUwEjgCssJyXvV4BhxM3y6oKuk0wBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCSZsPUeZvdKO5SoLVXnujHqj2L3RnbtWCV8jd3J/Dq7DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMAYsEjCm0IZfJ2Zmv7Hqp+CAEm6XaHjcvEMx0usIlSMtS+Nv5ZFuJBbsrx7kGbncOTBRMB0GCWCGSAFlAwQBKgQQVbZvllp7v53v+5zQE1RdVwQwd4dIDBJWocDNkETlUeIvQ7dE3k/0KNsFg5QUXIWZ49/pfDDHZ4cyaBAxm4pTVDUgMIIBFQIBAqAiBCAKaQVVewI74Q1xvI3qFj99IInXXHQpYwvCJGaHM2a3WTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAJTbV4mwvvX9QMIp7ZeI4vULr20xFVvIidWm5f8VLLRrMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZwA6LAIeLvksS/kjjsf5u0ON6KOkE3Na+Gr1YUN7D89SlGxoPM3AGS5Np8IhVXvNMFEwHQYJYIZIAWUDBAEqBBCxoYn5gb9l0DT8bXU/g9CZBDCID58W78ALWYdwoNtINpRxKNxdo7cic16XEG6z9KWWs8mEumowndsNL2dZPFvLpLcwggEVAgECoCIEIAuNcSL1B0U0778/hDjLqPkwtE8jO9YcZfhIgMXHa+msMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXpjJEOd7Ay5Bk+sCHZxL0LqjG2WGL7XiDXYb5nonPcUwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDvNhxjgDfrUdd04KW24RsXYc1nqFidBUxw7p9ItEt7plwkNTs2bzkMpHe7ufTQc3AwUTAdBglghkgBZQMEASoEEJHRiqJIuGuewZQVOv9rqCwEMIdasg5OxHuw1PHDd4bMqL0V3+FmSzxevYVDHYu9+M6KDmdDsYD2TbTnze6qQ2MyKTCCARUCAQKgIgQgF7uvNtMIAur6T5hUk8YmA+wS5l4nA/r1lsdhE94H29MwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB5dQD12I+x/u+A6nbvHSKS8BN5HURHBrCI+GjAyTqXHTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMEZuhCp3UsxPAkB58kKEvD9cAKIbOSG3Y/B8gCQn6VStsUqd+hlgT8xuJe9ZlXIzpTBRMB0GCWCGSAFlAwQBKgQQtcAXjSkyM/p6ai/dHH1ITAQwitM226Beplv6WD4WJb0IJS+4tu1DQ0Yc9jMoPH2Bv9GlElD6Ru3Yt6uwFIeI9IcDMIIBFQIBAqAiBCAnDrtwjOuscTQEPxvwxEZMMNw4hlDChj4KrIE9vjm8+jAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMbosYfz7z/c88WONdyQ3WBBZHDhGTM9lQ+NaAGNm0ZFMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQw+z/kd8iFoSsJ6oodl647M+uAZMUHtpbAskFLSlVybwIcO8Yukg1z1zi/wmohbI5JMFEwHQYJYIZIAWUDBAEqBBAT6xH+f9z8B40iX3V+FG3XBDBcKWor27gd3tPfwMrx+K55I6fDMVQuh96IWTvqxpiIDkHQNWcraI8iijGbKYOm4WcwggEVAgECoCIEIGSLvD61SgkWz7l3Zw9/N4rIBkR6n9Qo7Cs21gCn7AVjMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAGC9LfF1yG5JrBwGLFq1qJlcRl+ChOFG7jyTN4PXfiTwwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDD6IHUf8BozheyYWRW9VlZiIUjVUL/6sj9rRx0qV6CZ5hgHs5IZhKRDSkY1fsia6xIwUTAdBglghkgBZQMEASoEEAR8+jPqogiQWEjgoQ5qp/8EMMQgyW7+Lpj9sVsXpw7hPKtJMcR7ycqGDibmQCUR5kv+I2qoB4CFcKepeUcyXweiPDCCARUCAQKgIgQg7K3yFDemud3MKRJJxWpd2bSWm7rWjwjv7nmfvOlP+xwwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBOY0OO75qvwmMGABvaF8OD4EvKO0Luq9HnwrlcDBYl0DAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMCoDfRigXpu4jgqQJw5mq5SID+d6ey7bfGE27DQgpM++20wH0FVOk+pn5pEm3DKMkjBRMB0GCWCGSAFlAwQBKgQQ4ekdMtGF5pjpdrE/dqEZQAQwyg5JVAgoJYz4mokP5pxxpCZjxR1uHGby9stjwmdg7u8f10xhNMLrnwAQGBNCyBB2MIIBFQIBAqAiBCDx4+HMoUWy/zMQnEfOmK1IrftOktlCECCknqfJgIniyjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC/4OYAGOvfglstuwvmzMH0P897oW00UOJh8z9Oa4drkMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwuguHh66/rA23c1xW+Wrpjs0ZEBUiBxrrRvJeS/S1bKMDDwUHVK/Md9johoDMsbb7MFEwHQYJYIZIAWUDBAEqBBDvsCvGh4Md3BJrkbhjzwy7BDAbVyByTf2TeFeEqDywIfY/dQbQcMtmTD+2Bn/Y0HT1Z7ClAjrcKuxkB9W0Ys1L3FgwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMIe1v++T1huQVtzypcIEf22hv+SZqDTkIAjBWFv3ZouzgqZg9jHLYv6nA1IruM6OegDuBG4s/mm/PQ1bV8brJEZx5BwTuC/b03RhDs3j6LphSJ+8o" + }, + "sign_then_encrypt_single_recipient": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBjaHn6Z1QrXdAfRb034JoDhoXM+8hKYiQzQAg6+l419", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIICFQIBADCCAVsGCSqGSIb3DQEHA6CCAUwwggFIAgECMYIBGTCCARUCAQKgIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQB0YhufvezF6W/834kAB7o5LPquTik/0qkMLRlmP7fEGjAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMID/2OZvTt0cClysYG6ZVlKfmEGEJLl12gLZ07qRo3qtm4ARwRoweHtedbzpdRefXjBRMB0GCWCGSAFlAwQBKgQQVdMd5xQjd2DE16rGrBTqIwQw4YxHOLiK8mvvH8cMIPsU0rpsM0fe+ohMnHCaW5ccTdgSMCOyVjaDUMqpl+KvIF4GMCYGCSqGSIb3DQEHATAZBglghkgBZQMEAS4EDCZnr2AeX892Duem8KCBsDGBrTA7DBVWSVJHSUwtREFUQS1TSUdORVItSUSiIgQgQF9Aay6V4VGXDVrv1BknveFMztyCn1dt80nf7mqnj9IwbgwVVklSR0lMLURBVEEtU0lHTkFUVVJFolUEUzBRMA0GCWCGSAFlAwQCAwUABEC9GjnFrMcTJ7YKj46bDyQQ/EEUzuePFOSPk8RKjrFDFCLfLkYH9gVdUCjGrVv07/FcuKEd9ZS86G4tUuh3F9gC7EEbYUtjCnPL31rWnAKeqi04gUq1wFLA1YdtOvAqjZUc1N3LQ+oiTo1ErCJKhRhugpApO2V3YLl/tsU3NbrqQv1rPwjA12G8" + }, + "sign_then_encrypt_multiple_recipients": { + "private_keys": [ + "MC4CAQAwBQYDK2VwBCIEIAvWl/kgTqbXQ+cTytIUCZkfjOYv7W6g5eyawFabxScJ", + "MC4CAQAwBQYDK2VwBCIEICGXlHJDS+I7rrqawhJQOJ8XjgOCNasUQcWR6os5wYE4", + "MC4CAQAwBQYDK2VwBCIEIG0S2QFR6u0AOoj8jZhZSObL8NaguY/nVZYs1FVgDpI/", + "MC4CAQAwBQYDK2VwBCIEIGhP0N16y7vcZXNRnhkUyIXNIj90+Swg+w0LRzdDaCsd", + "MC4CAQAwBQYDK2VwBCIEINk1nCOxREjzxD06eprK790GoqNWtWuVAu0fOue9B6Pn" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgZ/5EW3CwoNqvth/AhFM99EUelekEMlGi6b58yOzdzUIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQAiNmc2Y/3No9n6K5HpV0Yj2kIJht68/Qxz2BPTZFcvkTAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMIZcBiKH2K5DjF7SRqOELqNPZp4GD0jY4/LoP+1kVSUNWJFNogeUdpsclpktDlcYozBRMB0GCWCGSAFlAwQBKgQQNIzOge5YjNvC95QG3W2oZQQwaxnJRb7j0n5+Doqd4VwbjXHxnYuOpWLDORxdhQjtaWrf8zqcW57ejT5w9GubDjxOMIIBFQIBAqAiBCBsXBt9/JYionc7FscmmxLkYqzQBlugvte3tBgR9+eyADAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAMDxkSWypMtiqVQ3avChkE9BP30ta0zctoS4WW0OKRDiMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwBmKs+uwujxGmZcBXVIMv8x2EwJLHkgybdFCrymxAkdcocbAUAR42b0CiecrTBtBqMFEwHQYJYIZIAWUDBAEqBBBnvbvZQTSrb1PaIPmJFox0BDAg9dLzHnUw/QV5lCSVv+tj7wx3ML0ZdXCN14Aielstx7wO2Ygg9ejJ6lzkSJNgJ9EwggEVAgECoCIEIG08tVe/WHb7d+FAaErZRgWQ6M18TWtx0/O1FWmUoKwFMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAMMR5Lljq+Y2g2cespAzlC23CvRJLFaHDsJJBPyWodeswGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDDIp0Rh1wwAYb73+t3oiNAT09GspVhS78fwElGFnTtmHzxSER/ugaixuEgzmkD5SdowUTAdBglghkgBZQMEASoEEM5LxKaK2b1dXyt8JXMaWaAEMMmMXWBr3QEB6YaaWwQMpGUQz7M3ri7WPPHtdpFMY1R9wt1quWU2eeFna7n7tKj3mTCCARUCAQKgIgQgpmRIy7nlVoGTkJBOHqEjKdeEcnJu5ahqfjYWrg+Z8oIwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQBilNAblc9gZ3yzTZHrUaYCdn64Perqaf4YmZXn+/QYGzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMJq9vHZAV4zu0cH5aMvCzBw6HqfiX0kzs4DI2WWPMmExTHfxlqbqB32+kS36HqH/cTBRMB0GCWCGSAFlAwQBKgQQMKacxhPe+eXxZ+sUXSI8/wQwbolTTcvEYTewC7Tyz29pd+FYnT92VdCM1ciI94PywbqZUUCbi32aR0AG1t5geUswMIIBFQIBAqAiBCDC0TMYmYbdpCd0fO+UBsN8Oyix6Q7NNXzVxpua0kGAwTAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAEtgpOVQm18owVuPctwdXbQ8iRv24HPf8i64fCbkB0i0MBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwZZ7cnK2Sq/KsP54qcN/su+ZEdtJIMunexuXzM2/GtW3yFDm13EPARvEwLiD/qZUOMFEwHQYJYIZIAWUDBAEqBBDphHjyT3NaJV/Rq+r/x4cvBDDtY+WdlzXUsfEQvGp2fBwM8xI6sZRbk68gUuZpCjFICeVsD8pdiS4RrjjnPMY2h1MwJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMtbmAUdn9qCGdQPOhoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCBn/kRbcLCg2q+2H8CEUz30RR6V6QQyUaLpvnzI7N3NQjBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQKaB09lKLNo5mLRLxl4S5nI0dbYxwGUYUzXXtdLXnWMf4fxCPR0USW1qyIQLVUeJmtIhET3R/VPhqRrPKsFzyQAB/jziUKj409ykG++1OQg2FE5XhMhQoiFhTf8Cxo2tDeOOXCeQCy1SiG5wYJVXkVXFFNN8b59rJEp8RTRnIR8OfV6MkJsZCS4=" + }, + "generate_signature": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIBueB+DRjfF52AK7qTkUUhOEOJwNpzxkt3d00riD7QuI", + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "signature": "MFEwDQYJYIZIAWUDBAIDBQAEQAp6LhuwBbtq2UILTQpvlBy+0rPgB9bNP45rU03arAogObdXGRD9bzEob7LzQNE8BWNF/JQY+pL0pC5Z3qH6tAc=" + }, + "sign_then_encrypt_multiple_signers": { + "private_key": "MC4CAQAwBQYDK2VwBCIEIG6wyMA56aGMaKf8kaDqo7j/5onSM3SN6Do5q3P28Xzp", + "public_keys": [ + "MCowBQYDK2VwAyEALSCsIR2pEK5SWR8k1kOqCjkLM7SEoMS98vO4TJ6GMC4=", + "MCowBQYDK2VwAyEA2AsShcg1ZpK5PdUsDpcRKXjs1BMcNb6jHxZ5cD0jYC8=", + "MCowBQYDK2VwAyEA2EOIbFIMSDdd5PebefEH5bAdGqeyFWaBDyKntr8SG2k=", + "MCowBQYDK2VwAyEAZoH5Fn31VuT7xClvY3cLoNMkSQqeR8fPxAEUERFYdSQ=", + "MCowBQYDK2VwAyEAVBmCMI5YvsyCDQv5gyZhm+uWyHTnhILe/K9CNKUqkLw=" + ], + "original_data": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", + "cipher_data": "MIIGeQIBADCCBb8GCSqGSIb3DQEHA6CCBbAwggWsAgECMYIFfTCCARUCAQKgIgQgV+lgOdbbR8aHUjIEx/YblRLUe/bGcH48E86p0I45JkMwBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCAIRQh5ho70Jl3wuIpZxMv7bRzWgZDoBFtZafbiXCp2jAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMNPkFuMoCS/A9nzgZQ5lie5laQnGcfPYZVm6iwxual6USPOF6oqZd0EJu2xKx188IzBRMB0GCWCGSAFlAwQBKgQQd1cWGby4gwQgB8MTRmQxwgQweMtdoScv4IEQu0jwTXgasA3LvgUOiIAeSvUSdiYlh55Vx6sTe7cXjoheLKclSWgLMIIBFQIBAqAiBCB06AofjB8oEBQU0dRxXdJsbOSUq7Xscawaz29Akghv+DAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAC8xBHqoj3SJ3lnrZRi4sKrLpAEv53VuyFeyyZr5parBMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwd/+fkUJ92w1AxbBGEtOZUQXVKplYlbfgZVxTdwPFEFaVxHkRf2DFLjYcA8eJxl+mMFEwHQYJYIZIAWUDBAEqBBB2sx1N39H6gkHGSSDxSWM+BDDQXM5d9avTHrLEzOOwWe3vtpFxkefz0/8T06c3UMxvhMp/TM3xYXgSQ1dDrDuMAVowggEVAgECoCIEIK8P8zsSxEpPs/6UDFfKP3/pz/Gas6c1VMnv7xUOhQVbMAcGAytlcAUABIHiMIHfAgEAMCowBQYDK2VwAyEAXjeOtEDF+FzRvyGoKlUwfuC+cbGonXmQ1lfbvClLHYMwGAYHKIGMcQIFAjANBglghkgBZQMEAgIFADBBMA0GCWCGSAFlAwQCAgUABDBSEicWwBP9gcdwbi3TlsX3YMWs3ue18iUUltu05uFruh+c2xYwTwo2Zt+oPNHT+mYwUTAdBglghkgBZQMEASoEEJaLW/UPxiYD1z4RQh0qMxMEMKVsy7VquNAYLvuaFdYJszzz5HtqlC9OnCiEOc9gecKL8KQ3bU0l4vL4pFl7SgBCJzCCARUCAQKgIgQgz3bkz4SRK/ndLceAz5A1rc4QpUdQsOKSg8Lpg9Yd29swBwYDK2VwBQAEgeIwgd8CAQAwKjAFBgMrZXADIQCjOgxFr+VCWdngH0SQMu6bfcUFqWooDGDut0G0t7RSEzAYBgcogYxxAgUCMA0GCWCGSAFlAwQCAgUAMEEwDQYJYIZIAWUDBAICBQAEMKADb3wAPzdJ+BsuKBB59pdL3HpV/hCRGtZtzHqfiIdTFsv+kMczigySgKGvysJrKzBRMB0GCWCGSAFlAwQBKgQQ/uq+33Aivg92/9lpF8feHQQwILYYaJz55qTzFwLe21a+oo9av0A/7mNBkqW4ogGn4/fOJ4T2Pwlt8kZor033rBHkMIIBFQIBAqAiBCDX7SnuiYY1nMfPaqFGbEssf4GXA3LlB97QLjJ+CjlazjAHBgMrZXAFAASB4jCB3wIBADAqMAUGAytlcAMhAHnBZCXOZ365uuylYUJcsG91xVq46zmnAKkDRI3uOAATMBgGByiBjHECBQIwDQYJYIZIAWUDBAICBQAwQTANBglghkgBZQMEAgIFAAQwM/lDhsv7B0Qq45Zi9pP7oKrlhzhtYlNk8Wh1uKA9mBWLqVQ61NlQVm9F2gk1gpPsMFEwHQYJYIZIAWUDBAEqBBDBBGvJ5lNVVw9/2/JU9ZHSBDA8y9XblGHB40qIniw+TeAt87peZP/mCYd4NCk91wt3perCNMhEJhoBq3KnB91Lyq4wJgYJKoZIhvcNAQcBMBkGCWCGSAFlAwQBLgQMXnmCLfBKuPnH+nxmoIGwMYGtMDsMFVZJUkdJTC1EQVRBLVNJR05FUi1JRKIiBCDPduTPhJEr+d0tx4DPkDWtzhClR1Cw4pKDwumD1h3b2zBuDBVWSVJHSUwtREFUQS1TSUdOQVRVUkWiVQRTMFEwDQYJYIZIAWUDBAIDBQAEQMbcL2CbQYHafMsmut9uyZ1c4cJGWk2cQZDZ8xcb/4EXeo/cJxFDhc59TVtjIImy8L4xpVLuI6+wGfwGIPmZKwlJubsUEUn+KHvHlS4z41YCsDrxXaDN8luv5jj+ERJg9MVrHttjMTOX0IIVoxcylbi6V2wd7/+KiL0JKx3dV5syJ4by+Y0y6eY=" + } +} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/Virgil.SDK.Tests.iOS.csproj b/SDK/Source/Virgil.SDK.Tests.iOS/Virgil.SDK.Tests.iOS.csproj new file mode 100644 index 00000000..743d891a --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/Virgil.SDK.Tests.iOS.csproj @@ -0,0 +1,192 @@ + + + + Debug + iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + Virgil.SDK.Tests.iOS + Virgil.SDK.Tests.iOS + Resources + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG; + prompt + 4 + iPhone Developer + true + true + true + true + true + Entitlements.plist + 29512 + None + x86_64 + HttpClientHandler + + + + + true + bin\iPhone\Release + + prompt + 4 + iPhone Developer + true + Entitlements.plist + SdkOnly + ARMv7, ARMv7s, ARM64 + HttpClientHandler + + + + pdbonly + true + bin\iPhoneSimulator\Release + + prompt + 4 + iPhone Developer + true + true + Entitlements.plist + None + x86_64 + HttpClientHandler + + + + true + full + false + bin\iPhone\Debug + DEBUG; + prompt + 4 + iPhone Developer + true + true + true + true + true + + 10695 + None + ARM64 + HttpClientHandler + + iOS Team Provisioning Profile: com.virgil11 + + + + + + + + ..\packages\Bogus.20.0.2\lib\netstandard2.0\Bogus.dll + + + ..\packages\PCLStorage.1.0.2\lib\portable-Xamarin.iOS+Xamarin.Mac\PCLStorage.Abstractions.dll + + + ..\packages\PCLStorage.1.0.2\lib\portable-Xamarin.iOS+Xamarin.Mac\PCLStorage.dll + + + + + ..\packages\System.Runtime.Loader.4.0.0\lib\netstandard1.5\System.Runtime.Loader.dll + + + ..\packages\NUnit.3.6.1\lib\Xamarin.iOS10\nunit.framework.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll + + + ..\packages\nunit.xamarin.3.6.1\lib\Xamarin.iOS\nunit.runner.iOS.dll + + + ..\packages\Virgil.Crypto.2.2.5\lib\xamarinios\Virgil.Crypto.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\Xamarin.iOS\PCLAppConfig.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\Xamarin.iOS\PCLAppConfig.FileSystemStream.Abstractions.dll + + + ..\packages\PCLAppConfig.0.3.4\lib\Xamarin.iOS\PCLAppConfig.FileSystemStream.dll + + + ..\packages\Newtonsoft.Json.11.0.1-beta3\lib\netstandard2.0\Newtonsoft.Json.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\Castle.Core.4.2.0\lib\netstandard1.3\Castle.Core.dll + + + ..\packages\NSubstitute.3.1.0\lib\netstandard1.3\NSubstitute.dll + + + + + + + + + + + + + + + + + + + + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + + + {DB5F3E5D-83FD-48BC-8842-95AA70A27928} + Virgil.SDK.iOS + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests.iOS/packages.config b/SDK/Source/Virgil.SDK.Tests.iOS/packages.config new file mode 100644 index 00000000..f42a326e --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests.iOS/packages.config @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/App.config.enc b/SDK/Source/Virgil.SDK.Tests/App.config.enc deleted file mode 100644 index 08e638b9..00000000 Binary files a/SDK/Source/Virgil.SDK.Tests/App.config.enc and /dev/null differ diff --git a/SDK/Source/Virgil.SDK.Tests/AppSettings.cs b/SDK/Source/Virgil.SDK.Tests/AppSettings.cs new file mode 100644 index 00000000..b861b143 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests/AppSettings.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Virgil.SDK.Tests +{ + public class AppSettings + { + public static string AppId = ConfigurationManager.AppSettings["virgil:AppID"]; + public static string AccounId = ConfigurationManager.AppSettings["virgil:AccountID"]; + public static string AppPrivateKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; + public static string ApiPublicKeyId = ConfigurationManager.AppSettings["virgil:AccessPublicKeyId"]; + public static string ApiPrivateKeyBase64 = ConfigurationManager.AppSettings["virgil:AccessPrivateKeyBase64"]; + public static string ServicePublicKeyDerBase64 = ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"]; + public static string CryptoCompatibilityData = System.IO.File.ReadAllText(ConfigurationManager.AppSettings["test:CryptoCompatibilityDataPath"]); + public static string OutputTestDataPath = ConfigurationManager.AppSettings["test:OutputDataPath"]; + public static string CardsServiceAddress = ConfigurationManager.AppSettings["virgil:CardsServicesAddressV5"]; + + public static string PrivateKeySTC31_1 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_1"]; + public static string PrivateKeySTC31_2 = ConfigurationManager.AppSettings["test:PrivateKeySTC31_2"]; + public static string PublicKeySTC32 = ConfigurationManager.AppSettings["test:PublicKeySTC32"]; + public static string OldKeyStoragePath = ConfigurationManager.AppSettings["test:OldKeyStoragePath"]; + public static string OldKeyAliase = ConfigurationManager.AppSettings["test:OldKeyAliase"]; + + public static string ImportedAccessPublicKeyId = ConfigurationManager.AppSettings["test:ImportedAccessPublicKeyId"]; + public static string ImportedAccessPublicKey = ConfigurationManager.AppSettings["test:ImportedAccessPublicKey"]; + + public static string PredefinedPrivateKeyBase64 = ConfigurationManager.AppSettings["test:PredefinedPrivateKeyBase64"]; + public static string ImportedJwt = ConfigurationManager.AppSettings["test:ImportedJwt"]; + } +} diff --git a/SDK/Source/Virgil.SDK.Tests/App_Example.config b/SDK/Source/Virgil.SDK.Tests/App_Example.config deleted file mode 100644 index 7b93fe88..00000000 --- a/SDK/Source/Virgil.SDK.Tests/App_Example.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/CardValidatorTests.cs b/SDK/Source/Virgil.SDK.Tests/CardValidatorTests.cs deleted file mode 100644 index 6e4b1322..00000000 --- a/SDK/Source/Virgil.SDK.Tests/CardValidatorTests.cs +++ /dev/null @@ -1,152 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Collections.Generic; - using FluentAssertions; - using NUnit.Framework; - - using Virgil.SDK.Client; - using Virgil.SDK.Common; - using Virgil.SDK.Cryptography; - - public class CardValidatorTests - { - [Test] - public void Validate_CardWithFakedOwnerSignature_ShouldReturnFalse() - { - var card = new CardModel(new PublishCardSnapshotModel - { - PublicKeyData = Convert.FromBase64String("MCowBQYDK2VwAyEAZzBtEQEWMQ9VeJrqSoO939VR5qimaTs4reqe9ut1VPk="), - }) - { - Id = "eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a", - Snapshot = Convert.FromBase64String("eyJpZGVudGl0eSI6ImFsaWNlIiwiaWRlbnRpdHlfdHlwZSI6Im1lbWJlciIsInB1YmxpY19rZXkiOiJNQ293QlFZREsyVndBeUVBWnpCdEVRRVdNUTlWZUpycVNvTzkzOVZSNXFpbWFUczRyZXFlOXV0MVZQaz0iLCJzY29wZSI6ImFwcGxpY2F0aW9uIiwiZGF0YSI6e30sImluZm8iOm51bGx9"), - Meta = new CardMetaModel - { - Version = "4.0", - Signatures = new Dictionary - { - ["eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQMpaO3OmXlsYhzR7pvF0Xuu7Dv84r3SRrmqjMvod9ik+oQ0M0uc+dwHNeNtQpy84qI14cXXaMAJDcfgtKyHPdA0="), - ["0b23070f8bafc48765658b92f168ae70b7638bc6fde0d246258de8a1116a52c4"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQJggpfBBpO9mHG2Q7hxdkY5b20krS4w4WG6IxNUHGmN1ZvKq0LECgNc2yuvXkDiSqXQ011zN1yhGwxe/LwtkZg8="), - ["3e29d43373348cfb373b7eae189214dc01d7237765e572db685839b64adca853"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQMpaO3OmXlsYhzR7pvF0Xuu7Dv84r3SRrmqjMvod9ik+oQ0M0uc+dwHNeNtQpy84qI14cXXaMAJDcfgtKyHPdA0="), - } - } - }; - - var crypto = new VirgilCrypto(); - var validator = new CardValidator(crypto); - validator.AddDefaultVerifiers(); - validator.Validate(card).Should().BeFalse(); - } - - [Test] - public void Validate_PredefinedCardGiven_ShouldReutrnTrue() - { - var card = new CardModel(new PublishCardSnapshotModel - { - PublicKeyData = Convert.FromBase64String("MCowBQYDK2VwAyEAZzBtEQEWMQ9VeJrqSoO939VR5qimaTs4reqe9ut1VPk="), - }) - { - Id = "eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a", - Snapshot = Convert.FromBase64String("eyJpZGVudGl0eSI6ImFsaWNlIiwiaWRlbnRpdHlfdHlwZSI6Im1lbWJlciIsInB1YmxpY19rZXkiOiJNQ293QlFZREsyVndBeUVBWnpCdEVRRVdNUTlWZUpycVNvTzkzOVZSNXFpbWFUczRyZXFlOXV0MVZQaz0iLCJzY29wZSI6ImFwcGxpY2F0aW9uIiwiZGF0YSI6e30sImluZm8iOm51bGx9"), - Meta = new CardMetaModel - { - Version = "4.0", - Signatures = new Dictionary - { - ["eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQFpw+jB5eDT1Dj3I2WqCewGqhAdG9f8pncAYeYcWHGWIONZlog1gjBb/y5/km8VbIPjrn4wlF0Ld8L5tRqRZOQM="), - ["0b23070f8bafc48765658b92f168ae70b7638bc6fde0d246258de8a1116a52c4"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQJggpfBBpO9mHG2Q7hxdkY5b20krS4w4WG6IxNUHGmN1ZvKq0LECgNc2yuvXkDiSqXQ011zN1yhGwxe/LwtkZg8="), - ["3e29d43373348cfb373b7eae189214dc01d7237765e572db685839b64adca853"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQMpaO3OmXlsYhzR7pvF0Xuu7Dv84r3SRrmqjMvod9ik+oQ0M0uc+dwHNeNtQpy84qI14cXXaMAJDcfgtKyHPdA0="), - } - } - }; - - var crypto = new VirgilCrypto(); - var validator = new CardValidator(crypto); - validator.AddDefaultVerifiers(); - validator.Validate(card).Should().BeTrue(); - } - - [Test] - public void Validate_CardWithFakedCardId_ShouldReturnFalse() - { - var card = new CardModel - { - Id = "3e29d43373348cfb373b7eae189214dc01d7237765e572db685839b64adca853", - Snapshot = Convert.FromBase64String("eyJpZGVudGl0eSI6ImFsaWNlIiwiaWRlbnRpdHlfdHlwZSI6Im1lbWJlciIsInB1YmxpY19rZXkiOiJNQ293QlFZREsyVndBeUVBWnpCdEVRRVdNUTlWZUpycVNvTzkzOVZSNXFpbWFUczRyZXFlOXV0MVZQaz0iLCJzY29wZSI6ImFwcGxpY2F0aW9uIiwiZGF0YSI6e30sImluZm8iOm51bGx9"), - Meta = new CardMetaModel - { - Version = "4.0" - } - }; - - var crypto = new VirgilCrypto(); - var validator = new CardValidator(crypto); - validator.AddDefaultVerifiers(); - validator.Validate(card).Should().BeFalse(); - } - - [Test] - public void ValidateWithoutDefaultVerifiers_CardWithoutServiceSignature_ShouldReturnTrue() - { - var card = new CardModel(new PublishCardSnapshotModel - { - PublicKeyData = Convert.FromBase64String("MCowBQYDK2VwAyEAZzBtEQEWMQ9VeJrqSoO939VR5qimaTs4reqe9ut1VPk="), - }) - { - Id = "eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a", - Snapshot = Convert.FromBase64String("eyJpZGVudGl0eSI6ImFsaWNlIiwiaWRlbnRpdHlfdHlwZSI6Im1lbWJlciIsInB1YmxpY19rZXkiOiJNQ293QlFZREsyVndBeUVBWnpCdEVRRVdNUTlWZUpycVNvTzkzOVZSNXFpbWFUczRyZXFlOXV0MVZQaz0iLCJzY29wZSI6ImFwcGxpY2F0aW9uIiwiZGF0YSI6e30sImluZm8iOm51bGx9"), - Meta = new CardMetaModel - { - Version = "4.0", - Signatures = new Dictionary - { - ["eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQFpw+jB5eDT1Dj3I2WqCewGqhAdG9f8pncAYeYcWHGWIONZlog1gjBb/y5/km8VbIPjrn4wlF0Ld8L5tRqRZOQM="), - ["0b23070f8bafc48765658b92f168ae70b7638bc6fde0d246258de8a1116a52c4"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQJggpfBBpO9mHG2Q7hxdkY5b20krS4w4WG6IxNUHGmN1ZvKq0LECgNc2yuvXkDiSqXQ011zN1yhGwxe/LwtkZg8=") - } - } - }; - - var crypto = new VirgilCrypto(); - var validator = new CardValidator(crypto); - validator.Validate(card).Should().BeTrue(); - } - - [Test] - public void ValidateWithDefaultVerifiers_CardWithoutServiceSignature_ShouldReturnFalse() - { - var card = new CardModel(new PublishCardSnapshotModel - { - PublicKeyData = Convert.FromBase64String("MCowBQYDK2VwAyEAZzBtEQEWMQ9VeJrqSoO939VR5qimaTs4reqe9ut1VPk="), - }) - { - Id = "eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a", - Snapshot = Convert.FromBase64String("eyJpZGVudGl0eSI6ImFsaWNlIiwiaWRlbnRpdHlfdHlwZSI6Im1lbWJlciIsInB1YmxpY19rZXkiOiJNQ293QlFZREsyVndBeUVBWnpCdEVRRVdNUTlWZUpycVNvTzkzOVZSNXFpbWFUczRyZXFlOXV0MVZQaz0iLCJzY29wZSI6ImFwcGxpY2F0aW9uIiwiZGF0YSI6e30sImluZm8iOm51bGx9"), - Meta = new CardMetaModel - { - Version = "4.0", - Signatures = new Dictionary - { - ["eb95e1b31ff3090598a05bf108c06088af5f70cfd6338924932396e9dfce840a"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQFpw+jB5eDT1Dj3I2WqCewGqhAdG9f8pncAYeYcWHGWIONZlog1gjBb/y5/km8VbIPjrn4wlF0Ld8L5tRqRZOQM="), - ["0b23070f8bafc48765658b92f168ae70b7638bc6fde0d246258de8a1116a52c4"] = - Convert.FromBase64String("MFEwDQYJYIZIAWUDBAICBQAEQJggpfBBpO9mHG2Q7hxdkY5b20krS4w4WG6IxNUHGmN1ZvKq0LECgNc2yuvXkDiSqXQ011zN1yhGwxe/LwtkZg8=") - } - } - }; - - var crypto = new VirgilCrypto(); - var validator = new CardValidator(crypto); - validator.AddDefaultVerifiers(); - validator.Validate(card).Should().BeFalse(); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/CardsManagerTests.cs b/SDK/Source/Virgil.SDK.Tests/CardsManagerTests.cs deleted file mode 100644 index 1fc5d230..00000000 --- a/SDK/Source/Virgil.SDK.Tests/CardsManagerTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.Configuration; - using NUnit.Framework; - using FluentAssertions; - using System.Threading.Tasks; - using Client; - - class CardsManagerTests - { - [Test] - public async Task PublishCardWithAppCredentials_PredefinedCard_ShouldPublishCard() - { - var clientParams = new VirgilClientParams(ConfigurationManager.AppSettings["virgil:AppAccessToken"]); - clientParams.SetCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsServicesAddress"]); - clientParams.SetIdentityServiceAddress(ConfigurationManager.AppSettings["virgil:IdentityServiceAddress"]); - clientParams.SetRAServiceAddress(ConfigurationManager.AppSettings["virgil:RAServicesAddress"]); - clientParams.SetReadCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsReadServicesAddress"]); - - // To use staging Verifier instead of default verifier - var cardVerifier = new CardVerifierInfo - { - CardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"], - PublicKeyData = VirgilBuffer.From(ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"], - StringEncoding.Base64) - }; - var virgil = new VirgilApi(new VirgilApiContext - { - Credentials = new AppCredentials - { - AppId = ConfigurationManager.AppSettings["virgil:AppID"], - AppKey = VirgilBuffer.FromFile(ConfigurationManager.AppSettings["virgil:AppKeyPath"]), - AppKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"] - }, - ClientParams = clientParams, - UseBuiltInVerifiers = false, - CardVerifiers = new[] { cardVerifier } - }); - - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - - await virgil.Cards.PublishAsync(aliceCard); - aliceCard.Id.Should().NotBeEmpty(); - - Assert.IsTrue(aliceCard.IsPairFor(aliceKey)); - await virgil.Cards.RevokeAsync(aliceCard); - } - - [Test] - public void PublishCardWithEmptyAppCredentials_PredefinedCard_ShouldOccurAppCredentialsException() - { - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - Assert.ThrowsAsync(() => virgil.Cards.PublishAsync(aliceCard)); - } - - [Test] - public void RevokeWithEmptyAppCredentials_PredefinedCard_ShouldOccurAppCredentialsException() - { - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - Assert.ThrowsAsync(() => virgil.Cards.RevokeAsync(aliceCard)); - } - } -} diff --git a/SDK/Source/Virgil.SDK.Tests/CreateCardRequestTests.cs b/SDK/Source/Virgil.SDK.Tests/CreateCardRequestTests.cs deleted file mode 100644 index 07a84d23..00000000 --- a/SDK/Source/Virgil.SDK.Tests/CreateCardRequestTests.cs +++ /dev/null @@ -1,125 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Collections.Generic; - using System.Text; - using FluentAssertions; - - using Newtonsoft.Json; - using NUnit.Framework; - - using Virgil.SDK.Common; - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - - public class CreateCardRequestTests - { - [Test] - public void Ctor_RequestDetailsGiven_ShouldSnapshotBeEquivalentToSerializedDetails() - { - var crypto = new VirgilCrypto(); - - var keyPair = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(keyPair.PublicKey); - - const string identity = "alice"; - const string identityType = "member"; - - var request = new PublishCardRequest - ( - identity, - identityType, - exportedPublicKey - ); - - var requestJson = Encoding.UTF8.GetString(request.Snapshot); - var requestModel = JsonConvert.DeserializeObject(requestJson); - - requestModel.Identity.ShouldBeEquivalentTo(identity); - requestModel.IdentityType.ShouldBeEquivalentTo(identityType); - requestModel.PublicKeyData.ShouldBeEquivalentTo(exportedPublicKey); - } - - [Test] - public void Ctor_NullAsParameterGiven_ShouldSnapshotBeEquivalentToSerializedDetails() - { - var crypto = new VirgilCrypto(); - - var keyPair = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(keyPair.PublicKey); - - const string identity = "alice"; - const string identityType = "member"; - - var request = new PublishCardRequest(identity, identityType, exportedPublicKey); - - var requestJson = Encoding.UTF8.GetString(request.Snapshot); - var requestModel = JsonConvert.DeserializeObject(requestJson); - - requestModel.Identity.ShouldBeEquivalentTo(identity); - requestModel.IdentityType.ShouldBeEquivalentTo(identityType); - requestModel.PublicKeyData.ShouldBeEquivalentTo(exportedPublicKey); - } - - [Test] - public void Export_WithoutParameters_ShouldReturnStringRepresentationOfRequest() - { - var crypto = new VirgilCrypto(); - var requestSigner = new RequestSigner(crypto); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - const string identity = "alice"; - const string identityType = "member"; - - var request = new PublishCardRequest(identity, identityType, exportedPublicKey); - - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - - var exportedRequest = request.Export(); - - var jsonData = Convert.FromBase64String(exportedRequest); - var json = Encoding.UTF8.GetString(jsonData); - var model = JsonConvert.DeserializeObject(json); - - model.ContentSnapshot.ShouldBeEquivalentTo(request.Snapshot); - model.Meta.Signatures.ShouldAllBeEquivalentTo(request.Signatures); - } - - [Test] - public void Export_WithoutParameters_ShouldBeEquivalentToImportedRequest() - { - var crypto = new VirgilCrypto(); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - const string identity = "alice"; - const string identityType = "member"; - - var request = new PublishCardRequest( - identity: identity, - identityType: identityType, - publicKeyData: exportedPublicKey, - customFields: new Dictionary - { - ["key1"] = "value1", - ["key2"] = "value2" - }, - info: new CardInfoModel - { - Device = "Device", - DeviceName = "DeviceName" - }); - - var requestSigner = new RequestSigner(crypto); - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - - var exportedRequest = request.Export(); - var importedRequest = new PublishCardRequest(exportedRequest); - - request.ShouldBeEquivalentTo(importedRequest); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/DigitalSignatureTest.cs b/SDK/Source/Virgil.SDK.Tests/DigitalSignatureTest.cs deleted file mode 100644 index a679cb69..00000000 --- a/SDK/Source/Virgil.SDK.Tests/DigitalSignatureTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.IO; - using System.Text; - using Cryptography; - using FluentAssertions; - using NUnit.Framework; - - public class DigitalSignatureTest - { - [Test] - public void SignData_PlainTextGiven_ShouldPassVerfifcation() - { - var crypto = new VirgilCrypto(); - - var keyPair = crypto.GenerateKeys(); - var data = Encoding.UTF8.GetBytes("Hello Bob!"); - - var signature = crypto.Sign(data, keyPair.PrivateKey); - - crypto.Verify(data, signature, keyPair.PublicKey).Should().BeTrue(); - } - - [Test] - public void SignData_StreamGiven_ShouldPassVerification() - { - var crypto = new VirgilCrypto(); - - var keyPair = crypto.GenerateKeys(); - var data = Encoding.UTF8.GetBytes("Hello Bob!"); - - byte[] signature; - - using (var inputStream = new MemoryStream(data)) - { - signature = crypto.Sign(inputStream, keyPair.PrivateKey); - } - - using (var inputStream = new MemoryStream(data)) - { - crypto.Verify(inputStream, signature, keyPair.PublicKey).Should().BeTrue(); - } - } - - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/EncryptionTest.cs b/SDK/Source/Virgil.SDK.Tests/EncryptionTest.cs deleted file mode 100644 index 2855310a..00000000 --- a/SDK/Source/Virgil.SDK.Tests/EncryptionTest.cs +++ /dev/null @@ -1,198 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; - - using FluentAssertions; - using NUnit.Framework; - - using Virgil.SDK.Cryptography; - - public class EncryptionTest - { - [Test] - public void EncryptData_SinglePublicKeyGiven_ShouldCipherDataBeDecrypted() - { - var crypto = new VirgilCrypto(); - - var keyPair = crypto.GenerateKeys(); - - var data = Encoding.UTF8.GetBytes("Encrypt me!!!"); - var encryptedData = crypto.Encrypt(data, keyPair.PublicKey); - var decryptedData = crypto.Decrypt(encryptedData, keyPair.PrivateKey); - - data.ShouldAllBeEquivalentTo(decryptedData); - } - - [Test] - public void EncryptData_MultiplePublicKeysGiven_ShouldCipherDataBeDecrypted() - { - var crypto = new VirgilCrypto(); - var keyPairs = new List(); - - for (var index = 0; index < 10; index++) - { - keyPairs.Add(crypto.GenerateKeys()); - } - - var data = Encoding.UTF8.GetBytes("Encrypt me!!!"); - var encryptedData = crypto.Encrypt(data, keyPairs.Select(it => it.PublicKey).ToArray()); - - foreach (var keyPair in keyPairs) - { - var decryptedData = crypto.Decrypt(encryptedData, keyPair.PrivateKey); - data.ShouldAllBeEquivalentTo(decryptedData); - } - } - - [Test] - public void EncryptData_MultiplePublicKeysWithDifferentTypesGiven_ShouldCipherDataBeDecrypted() - { - var crypto = new VirgilCrypto(); - var keyPairs = new List - { - crypto.GenerateKeys(KeyPairType.EC_SECP256R1), - crypto.GenerateKeys(KeyPairType.EC_SECP384R1), - crypto.GenerateKeys(KeyPairType.EC_SECP521R1), - crypto.GenerateKeys(KeyPairType.EC_BP256R1), - crypto.GenerateKeys(KeyPairType.EC_BP384R1), - crypto.GenerateKeys(KeyPairType.EC_BP512R1), - crypto.GenerateKeys(KeyPairType.EC_SECP256K1), - crypto.GenerateKeys(KeyPairType.EC_CURVE25519), - crypto.GenerateKeys(KeyPairType.FAST_EC_ED25519), - crypto.GenerateKeys(KeyPairType.FAST_EC_X25519) - }; - - var data = Encoding.UTF8.GetBytes("Encrypt me!!!"); - var encryptedData = crypto.Encrypt(data, keyPairs.Select(it => it.PublicKey).ToArray()); - - foreach (var keyPair in keyPairs) - { - var decryptedData = crypto.Decrypt(encryptedData, keyPair.PrivateKey); - data.ShouldAllBeEquivalentTo(decryptedData); - } - } - - [Test] - public void EncryptStream_SinglePublicKeyGiven_ShouldCipherStreamBeDecrypted() - { - var crypto = new VirgilCrypto(); - var keyPair = crypto.GenerateKeys(); - - var originalData = Encoding.UTF8.GetBytes(IntegrationHelper.RandomText); - - using (var inputStream = new MemoryStream(originalData)) - using (var cipherStream = new MemoryStream()) - using (var resultStream = new MemoryStream()) - { - crypto.Encrypt(inputStream, cipherStream, keyPair.PublicKey); - - using (var cipherStream1 = new MemoryStream(cipherStream.ToArray())) - { - crypto.Decrypt(cipherStream1, resultStream, keyPair.PrivateKey); - - resultStream.ToArray().ShouldAllBeEquivalentTo(originalData); - } - } - } - - public void EncryptStream_SmallStreamBufferGiven_ShouldCipherStreamBeDecrypted() - { - var crypto = new VirgilCrypto(); - var keyPair = crypto.GenerateKeys(); - - var originalData = Encoding.UTF8.GetBytes("Hello There :)"); - - byte[] cipherData; - byte[] resultData; - - using (var inputStream = new MemoryStream(originalData)) - using (var cipherStream = new MemoryStream()) - { - crypto.Encrypt(inputStream, cipherStream, keyPair.PublicKey); - cipherData = cipherStream.ToArray(); - } - - using (var cipherStream = new MemoryStream(cipherData)) - using (var resultStream = new MemoryStream()) - { - crypto.Decrypt(cipherStream, resultStream, keyPair.PrivateKey); - resultData = resultStream.ToArray(); - } - - originalData.ShouldAllBeEquivalentTo(resultData); - } - - [Test] - public void EncryptStream_MultiplePublicKeysGiven_ShouldCipherStreamBeDecrypted() - { - var crypto = new VirgilCrypto(); - var keyPairs = new List - { - crypto.GenerateKeys(KeyPairType.EC_SECP256R1), - crypto.GenerateKeys(KeyPairType.EC_SECP384R1), - crypto.GenerateKeys(KeyPairType.EC_SECP521R1), - crypto.GenerateKeys(KeyPairType.EC_BP256R1), - crypto.GenerateKeys(KeyPairType.EC_BP384R1), - crypto.GenerateKeys(KeyPairType.EC_BP512R1), - crypto.GenerateKeys(KeyPairType.EC_SECP256K1), - crypto.GenerateKeys(KeyPairType.EC_CURVE25519), - crypto.GenerateKeys(KeyPairType.FAST_EC_ED25519), - crypto.GenerateKeys(KeyPairType.FAST_EC_X25519) - }; - - var originalData = Encoding.UTF8.GetBytes(IntegrationHelper.RandomText); - - foreach (var keyPair in keyPairs) - { - using (var inputStream = new MemoryStream(originalData)) - using (var cipherStream = new MemoryStream()) - using (var resultStream = new MemoryStream()) - { - crypto.Encrypt(inputStream, cipherStream, keyPairs.Select(it => it.PublicKey).ToArray()); - - using (var cipherStream1 = new MemoryStream(cipherStream.ToArray())) - { - crypto.Decrypt(cipherStream1, resultStream, keyPair.PrivateKey); - - resultStream.ToArray().ShouldAllBeEquivalentTo(originalData); - } - } - } - } - - [Test] - public void SignAndEncryptData_PublicAndPrivateKeysGiven_ShouldDecryptAndVerifyDataSuccessfully() - { - var crypto = new VirgilCrypto(); - - var alice = crypto.GenerateKeys(); - var bob = crypto.GenerateKeys(); - - var originalData = Encoding.UTF8.GetBytes(IntegrationHelper.RandomText); - var cipherData = crypto.SignThenEncrypt(originalData, alice.PrivateKey, bob.PublicKey); - - var decryptedData = crypto.DecryptThenVerify(cipherData, bob.PrivateKey, alice.PublicKey); - decryptedData.ShouldAllBeEquivalentTo(originalData); - } - - [Test] - public void SignAndEncryptData_ListOfPublicAndPrivateKeysGiven_ShouldDecryptAndVerifyDataSuccessfully() - { - var crypto = new VirgilCrypto(); - - var alice = crypto.GenerateKeys(); - var bob = crypto.GenerateKeys(); - var jacob = crypto.GenerateKeys(); - - var originalData = Encoding.UTF8.GetBytes(IntegrationHelper.RandomText); - var cipherData = crypto.SignThenEncrypt(originalData, alice.PrivateKey, bob.PublicKey); - - // verify that a message is from one of the trusted keys - var decryptedData = crypto.DecryptThenVerify(cipherData, bob.PrivateKey, jacob.PublicKey, alice.PublicKey); - decryptedData.ShouldAllBeEquivalentTo(originalData); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/FingerprintTests.cs b/SDK/Source/Virgil.SDK.Tests/FingerprintTests.cs deleted file mode 100644 index 6b0aa6f6..00000000 --- a/SDK/Source/Virgil.SDK.Tests/FingerprintTests.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.Text; - - using FluentAssertions; - using NUnit.Framework; - - using Virgil.Crypto; - using Virgil.SDK.Cryptography; - - public class FingerprintTests - { - [Test] - public void Ctor_HexStringGiven_ValuesShouldMatchWithVirgilCryptoImpl() - { - var hash = new VirgilCrypto().ComputeHash(Encoding.UTF8.GetBytes("1234567890"), HashAlgorithm.SHA256); - var hex = VirgilByteArrayUtils.BytesToHex(hash); - - hash.ShouldAllBeEquivalentTo(new Fingerprint(hex).GetValue()); - } - - [Test] - public void Ctor_ByteArrayGiven_HexStringShouldMatchWithVirgilCryptoImpl() - { - var hash = new VirgilCrypto().ComputeHash(Encoding.UTF8.GetBytes("1234567890"), HashAlgorithm.SHA256); - var hex = VirgilByteArrayUtils.BytesToHex(hash); - - hex.Should().Be(new Fingerprint(hash).ToHEX()); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/GeneratorTestData.cs b/SDK/Source/Virgil.SDK.Tests/GeneratorTestData.cs new file mode 100644 index 00000000..7c0bb694 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests/GeneratorTestData.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Bogus; +using NSubstitute; +using NUnit.Framework; +using Virgil.CryptoImpl; +using Virgil.SDK.Common; +using Virgil.SDK.Signer; +using Virgil.SDK.Verification; +using Virgil.SDK.Web; +using Virgil.SDK.Web.Authorization; + +namespace Virgil.SDK.Tests.Shared +{ + [TestFixture] + class GeneratorTestData + { + private readonly Faker faker = new Faker(); + + [Test] + public async System.Threading.Tasks.Task Prepair_TestDataAsync() + { + var model = faker.PredefinedRawSignedModel(); + var fullModel = faker.PredefinedRawSignedModel( + "a666318071274adb738af3f67b8c7ec29d954de2cabfd71a942e6ea38e59fff9", + true, true, true); + var data = new Dictionary + { + { "STC-1.as_string", model.ExportAsString()}, + { "STC-1.as_json", model.ExportAsJson()}, + { "STC-2.as_string", fullModel.ExportAsString()}, + { "STC-2.as_json", fullModel.ExportAsJson()} + }; + + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromString(model.ExportAsString()); + var crypto = new VirgilCrypto(); + + data.Add("STC-3.as_string", cardManager.ExportCardAsString(card)); + data.Add("STC-3.as_json", cardManager.ExportCardAsJson(card)); + data.Add("STC-3.card_id", card.Id); + data.Add("STC-3.public_key_base64", Bytes.ToString(crypto.ExportPublicKey(card.PublicKey), StringEncoding.BASE64)); + + fullModel = faker.PredefinedRawSignedModel(null, true, true, true); + var fullCard = cardManager.ImportCardFromString(fullModel.ExportAsString()); + + data.Add("STC-4.as_string", cardManager.ExportCardAsString(fullCard)); + data.Add("STC-4.as_json", cardManager.ExportCardAsJson(fullCard)); + data.Add("STC-4.card_id", fullCard.Id); + data.Add("STC-4.public_key_base64", Bytes.ToString(crypto.ExportPublicKey(fullCard.PublicKey), + StringEncoding.BASE64)); + foreach (var signature in fullCard.Signatures) + { + data.Add($"STC-4.signature_{signature.Signer}_base64", Bytes.ToString(signature.Signature, + StringEncoding.BASE64)); + } + + string apiPublicKeyId; + string apiPublicKeyBase64; + var (token, jwtGenerator) = faker.PredefinedToken( + new VirgilAccessTokenSigner(), + TimeSpan.FromMinutes(10), + out apiPublicKeyId, + out apiPublicKeyBase64); + + data.Add("STC-22.jwt", token.ToString()); + data.Add("STC-22.api_public_key_base64", apiPublicKeyBase64); + data.Add("STC-22.api_key_id", apiPublicKeyId); + + + data.Add("STC-23.api_public_key_base64", apiPublicKeyBase64); + data.Add("STC-23.api_key_id", apiPublicKeyId); + data.Add("STC-23.app_id", jwtGenerator.AppId); + + data.Add("STC-23.api_private_key_base64", Bytes.ToString( + crypto.ExportPrivateKey(jwtGenerator.ApiKey), StringEncoding.BASE64)); + + // STC-10 + var cardKeyPair = crypto.GenerateKeys(); + var cardIdentity = faker.Random.AlphaNumeric(10); + var rawCardContent1 = new RawCardContent() + { + CreatedAt = DateTime.UtcNow, + Identity = cardIdentity, + PublicKey = crypto.ExportPublicKey(cardKeyPair.PublicKey), + Version = "5.0", + }; + var rawSignedModel = new RawSignedModel() { ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent1) }; + + var signer = new ModelSigner(new VirgilCardCrypto()); + signer.SelfSign(rawSignedModel, cardKeyPair.PrivateKey); + + + var keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "extra" + }); + data.Add("STC-10.private_key1_base64", Bytes.ToString( + crypto.ExportPrivateKey(keyPair.PrivateKey), StringEncoding.BASE64)); + + var accessTokenGenerator = new JwtGenerator( + AppSettings.AppId, + IntegrationHelper.ApiPrivateKey(), + AppSettings.ApiPublicKeyId, + TimeSpan.FromMinutes(10), + new VirgilAccessTokenSigner() + ); + var accessTokenProvider = Substitute.For(); + accessTokenProvider.GetTokenAsync(Arg.Any()).Returns( + accessTokenGenerator.GenerateToken(cardIdentity) + ); + var validator = new VirgilCardVerifier(new VirgilCardCrypto()) { VerifySelfSignature = true, VerifyVirgilSignature = true }; + validator.ChangeServiceCreds(AppSettings.ServicePublicKeyDerBase64); + var manager = new CardManager(new CardManagerParams() + { + CardCrypto = new VirgilCardCrypto(), + AccessTokenProvider = accessTokenProvider, + ApiUrl = AppSettings.CardsServiceAddress, + Verifier = validator + }); + card = await manager.PublishCardAsync(rawSignedModel); + data.Add("STC-10.as_string", manager.ExportCardAsString(card)); + + + // STC - 11 + rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + data.Add("STC-11.as_string", rawSignedModel.ExportAsString()); + + // STC - 12 + rawSignedModel = faker.PredefinedRawSignedModel(null, true, false, false); + data.Add("STC-12.as_string", rawSignedModel.ExportAsString()); + + // STC - 14 + rawSignedModel = faker.PredefinedRawSignedModel(null, false, true, false); + data.Add("STC-14.as_string", rawSignedModel.ExportAsString()); + + // STC - 15 + rawSignedModel = faker.PredefinedRawSignedModel(null, false, false, false); + keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "self" + }); + data.Add("STC-15.as_string", rawSignedModel.ExportAsString()); + + // STC - 16 + rawSignedModel = faker.PredefinedRawSignedModel(null, true, true, false); + keyPair = crypto.GenerateKeys(); + signer.Sign(rawSignedModel, new SignParams() + { + SignerPrivateKey = keyPair.PrivateKey, + Signer = "extra" + }); + data.Add("STC-16.as_string", rawSignedModel.ExportAsString()); + data.Add("STC-16.public_key1_base64", Bytes.ToString( + crypto.ExportPublicKey(keyPair.PublicKey), StringEncoding.BASE64)); + + // STC - 28 + (token, jwtGenerator) = faker.PredefinedToken( + new VirgilAccessTokenSigner(), + TimeSpan.FromMinutes(2), + out apiPublicKeyId, + out apiPublicKeyBase64); + data.Add("STC-28.jwt", token.ToString()); + data.Add("STC-28.jwt_identity", token.BodyContent.Identity); + data.Add("STC-28.jwt_app_id", token.BodyContent.AppId); + data.Add("STC-28.jw_issuer", token.BodyContent.Issuer); + data.Add("STC-28.jwt_subject", token.BodyContent.Subject); + data.Add("STC-28.jwt_additional_data", Configuration.Serializer.Serialize(token.BodyContent.AdditionalData)); + data.Add("STC-28.jwt_expires_at", Configuration.Serializer.Serialize(token.BodyContent.ExpiresAt)); + data.Add("STC-28.jwt_issued_at", Configuration.Serializer.Serialize(token.BodyContent.IssuedAt)); + data.Add("STC-28.jwt_algorithm", token.HeaderContent.Algorithm); + data.Add("STC-28.jwt_api_key_id", token.HeaderContent.KeyId); + data.Add("STC-28.jwt_content_type", token.HeaderContent.ContentType); + data.Add("STC-28.jwt_type", token.HeaderContent.Type); + data.Add("STC-28.jwt_signature_base64", Bytes.ToString(token.SignatureData, StringEncoding.BASE64)); + + + // STC - 29 + (token, jwtGenerator) = faker.PredefinedToken( + new VirgilAccessTokenSigner(), + TimeSpan.FromDays(365), + out apiPublicKeyId, + out apiPublicKeyBase64); + data.Add("STC-29.jwt", token.ToString()); + data.Add("STC-29.jwt_identity", token.BodyContent.Identity); + data.Add("STC-29.jwt_app_id", token.BodyContent.AppId); + data.Add("STC-29.jw_issuer", token.BodyContent.Issuer); + data.Add("STC-29.jwt_subject", token.BodyContent.Subject); + data.Add("STC-29.jwt_additional_data", Configuration.Serializer.Serialize(token.BodyContent.AdditionalData)); + data.Add("STC-29.jwt_expires_at", Configuration.Serializer.Serialize(token.BodyContent.ExpiresAt)); + data.Add("STC-29.jwt_issued_at", Configuration.Serializer.Serialize(token.BodyContent.IssuedAt)); + data.Add("STC-29.jwt_algorithm", token.HeaderContent.Algorithm); + data.Add("STC-29.jwt_api_key_id", token.HeaderContent.KeyId); + data.Add("STC-29.jwt_content_type", token.HeaderContent.ContentType); + data.Add("STC-29.jwt_type", token.HeaderContent.Type); + data.Add("STC-29.jwt_signature_base64", Bytes.ToString(token.SignatureData, StringEncoding.BASE64)); + + + // STC - 34 + keyPair = crypto.GenerateKeys(); + var rawCardContent = new RawCardContent() + { + CreatedAt = DateTime.UtcNow, + Identity = "test", + PublicKey = crypto.ExportPublicKey(keyPair.PublicKey), + Version = "5.0" + }; + model = new RawSignedModel() { ContentSnapshot = SnapshotUtils.TakeSnapshot(rawCardContent) }; + + signer.SelfSign( + model, keyPair.PrivateKey, new Dictionary() { { "info", "some_additional_info" } } + ); + + data.Add("STC-34.private_key_base64", Bytes.ToString( + crypto.ExportPrivateKey(keyPair.PrivateKey), StringEncoding.BASE64)); + data.Add("STC-34.public_key_base64", Bytes.ToString( + crypto.ExportPublicKey(keyPair.PublicKey), StringEncoding.BASE64)); + data.Add("STC-34.self_signature_snapshot_base64", + Bytes.ToString(model.Signatures.First().Snapshot, StringEncoding.BASE64)); + data.Add("STC-34.content_snapshot_base64", + Bytes.ToString( + SnapshotUtils.TakeSnapshot(rawCardContent), StringEncoding.BASE64)); + data.Add("STC-34.as_string", model.ExportAsString()); + + System.IO.File.WriteAllText(AppSettings.OutputTestDataPath, + Configuration.Serializer.Serialize(data)); + + + } + /* + + [Test] + public void Prepair_TestData() + { + var rawSignedModel = faker.PredefinedRawSignedModel(); + var cardManager = faker.CardManager(); + var card = cardManager.ImportCardFromString(rawSignedModel.ExportAsString()); + + var fullrawSignedModel = faker.PredefinedRawSignedModel(null, true, true, true); + var fullCard = cardManager.ImportCardFromString(fullrawSignedModel.ExportAsString()); + + var data = new Dictionary + { + { "3_as_string", cardManager.ExportCardAsString(card) }, + { "3_as_json", cardManager.ExportCardAsJson(card) }, + { "4_as_string", cardManager.ExportCardAsString(fullCard)}, + { "4_as_json", cardManager.ExportCardAsJson(fullCard)} + }; + System.IO.File.WriteAllText(@"C:\Users\Vasilina\Documents\test_data_3_4", + Configuration.Serializer.Serialize(data)); + System.IO.File.AppendAllText(@"C:\Users\Vasilina\Documents\raw_data_3", cardManager.ExportCardAsJson(card)); + System.IO.File.AppendAllText(@"C:\Users\Vasilina\Documents\raw_data_4", cardManager.ExportCardAsJson(fullCard)); + }*/ + } +} diff --git a/SDK/Source/Virgil.SDK.Tests/HighLevelCryptoTests.cs b/SDK/Source/Virgil.SDK.Tests/HighLevelCryptoTests.cs deleted file mode 100644 index 702d85f5..00000000 --- a/SDK/Source/Virgil.SDK.Tests/HighLevelCryptoTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.Configuration; - using NUnit.Framework; - using FluentAssertions; - using System.Collections.Generic; - - public class HighLevelCryptoTests - { - [Test] - public void Decrypt_PredefinedCipherDataGiven_ShouldCipherDataBeDecrypted() - { - // Create Alice's card - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - - // Encrypt some message - var message = "Encrypt me, please!"; - var cipherData = aliceCard.Encrypt(VirgilBuffer.From(message)); - - // Somehow transfer encrypted message as Base64 string - var transferData = cipherData.ToString(StringEncoding.Base64); - - // Decrypt received message - var receivedCipherData = VirgilBuffer.From(transferData, StringEncoding.Base64); - var decryptedMessage = aliceKey.Decrypt(receivedCipherData); - - message.ShouldBeEquivalentTo(decryptedMessage.ToString()); - } - - [Test] - public void Verify_GivenMessageAndSignature_ShouldSignedDataBeVerified() - { - // Create Alice's key - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - - // Sign some message - var message = "Encrypt me, please!"; - var signature = aliceKey.Sign(VirgilBuffer.From(message)); - - // Somehow transfer signature as Base64 string - var transferSignatureData = signature.ToString(StringEncoding.Base64); - - // Verify message by Alice's Card using received signature - var receivedSignature = VirgilBuffer.From(transferSignatureData, StringEncoding.Base64); - var isVerified = aliceCard.Verify(message, receivedSignature); - - isVerified.ShouldBeEquivalentTo(true); - } - - [Test] - public void DecryptThenVerifyBySingleCard_EncryptedMessage_ShouldGivenMessageBeDecryptedAndVerified() - { - // Create Alice's key - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - var bobKey = virgil.Keys.Generate(); - var bobCard = virgil.Cards.Create("BobCard", bobKey); - var samCard = virgil.Cards.Create("SamCard", virgil.Keys.Generate()); - - // Alice signs some message then ecrypt it for Bob and Sam - var message = "Encrypt me, please!"; - var signedAndEncryptedMessage = aliceKey.SignThenEncrypt(VirgilBuffer.From(message), - new List(){ bobCard, samCard }); - - // Somehow transfer signed and encrypted message as Base64 string - var transferMessage = signedAndEncryptedMessage.ToString(StringEncoding.Base64); - - // Bob tries to decrypt and verify message - var receivedMessage = VirgilBuffer.From(transferMessage, StringEncoding.Base64); - var decryptedAneVerifiedMessage = bobKey.DecryptThenVerify(receivedMessage, aliceCard); - - decryptedAneVerifiedMessage.ToString().ShouldBeEquivalentTo(message); - } - - [Test] - public void DecryptThenVerifyByListOfTrustedCard_EncryptedMessage_ShouldGivenMessageBeDecryptedAndVerified() - { - // Create Alice's key - var AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - var virgil = new VirgilApi(AppAccessToken); - var aliceKey = virgil.Keys.Generate(); - var aliceCard = virgil.Cards.Create("AliceCard", aliceKey); - var bobKey = virgil.Keys.Generate(); - var bobCard = virgil.Cards.Create("BobCard", bobKey); - var samCard = virgil.Cards.Create("SamCard", virgil.Keys.Generate()); - - // Alice signs some message then ecrypt it for Bob and Sam - var message = "Encrypt me, please!"; - var signedAndEncryptedMessage = aliceKey.SignThenEncrypt(VirgilBuffer.From(message), - new List() { bobCard, samCard }); - - // Somehow transfer signed and encrypted message as Base64 string - var transferMessage = signedAndEncryptedMessage.ToString(StringEncoding.Base64); - - // Bob tries to decrypt and verify message - var receivedMessage = VirgilBuffer.From(transferMessage, StringEncoding.Base64); - var decryptedAneVerifiedMessage = bobKey.DecryptThenVerify(receivedMessage, samCard, aliceCard); - - decryptedAneVerifiedMessage.ToString().ShouldBeEquivalentTo(message); - } - - - - } -} diff --git a/SDK/Source/Virgil.SDK.Tests/HighLevelTests.cs b/SDK/Source/Virgil.SDK.Tests/HighLevelTests.cs deleted file mode 100644 index cefb45a3..00000000 --- a/SDK/Source/Virgil.SDK.Tests/HighLevelTests.cs +++ /dev/null @@ -1,135 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Collections.Generic; - using System.Dynamic; - using System.Linq; - using System.Threading.Tasks; - using Exceptions; - using Virgil.SDK.Client; - using Virgil.SDK.Common; - using Virgil.SDK.Cryptography; - - using Newtonsoft.Json; - using NUnit.Framework; - using Storage; - - public class HighLevelTests - { - [Test] - public void Crossplatform_Compatibility_Test() - { - var crypto = new VirgilCrypto(); - - dynamic testData = new ExpandoObject(); - - // Encrypt for single recipient - - { - var kp = crypto.GenerateKeys(); - var prkey = crypto.ExportPrivateKey(kp.PrivateKey); - var data = System.Text.Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - - testData.encrypt_single_recipient = new - { - private_key = prkey, - original_data = data, - cipher_data = crypto.Encrypt(data, kp.PublicKey) - }; - } - - // Encrypt for multiple recipients - - { - var kps = new int[new Random().Next(5, 10)].Select(it => crypto.GenerateKeys()).ToList(); - var prkeys = kps.Select(kp => crypto.ExportPrivateKey(kp.PrivateKey)).ToArray(); - var data = System.Text.Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - - testData.encrypt_multiple_recipients = new - { - private_keys = prkeys, - original_data = data, - cipher_data = crypto.Encrypt(data, kps.Select(kp => kp.PublicKey).ToArray()) - }; - } - - // Sign and Encrypt for single recipient - - { - var kp = crypto.GenerateKeys(); - var prkey = crypto.ExportPrivateKey(kp.PrivateKey); - var data = System.Text.Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - - testData.sign_then_encrypt_single_recipient = new - { - private_key = prkey, - original_data = data, - cipher_data = crypto.SignThenEncrypt(data, kp.PrivateKey, kp.PublicKey) - }; - } - - // Sign and encrypt for multiple recipients - - { - var kps = new int[new Random().Next(5, 10)].Select(it => crypto.GenerateKeys()).ToList(); - var prkeys = kps.Select(kp => crypto.ExportPrivateKey(kp.PrivateKey)).ToArray(); - var data = System.Text.Encoding.UTF8.GetBytes("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - - testData.sign_then_encrypt_multiple_recipients = new - { - private_keys = prkeys, - original_data = data, - cipher_data = - crypto.SignThenEncrypt(data, kps[0].PrivateKey, kps.Select(kp => kp.PublicKey).ToArray()) - }; - } - - // Generate Signature - - { - var kp = crypto.GenerateKeys(); - var prkey = crypto.ExportPrivateKey(kp.PrivateKey); - var data = System.Text.Encoding.UTF8.GetBytes("Suspendisse elit purus, laoreet ut nibh nec."); - - testData.generate_signature = new - { - private_key = prkey, - original_data = data, - signature = crypto.Sign(data, kp.PrivateKey) - }; - } - - // Export and Import SignableRequest - - { - var kp = crypto.GenerateKeys(); - var prkey = crypto.ExportPrivateKey(kp.PrivateKey); - var req = new PublishCardRequest( - identity: "alice", - identityType: "member", - publicKeyData: crypto.ExportPublicKey(kp.PublicKey), - customFields: new Dictionary - { - ["Key1"] = "Value1", - ["Key2"] = "Value2" - }, - info: new CardInfoModel - { - Device = "iPhone 7", - DeviceName = "My precious" - } - ); - var reqSigner = new RequestSigner(crypto); - reqSigner.SelfSign(req, kp.PrivateKey); - - testData.export_signable_request = new - { - private_key = prkey, - exported_request = req.Export() - }; - } - - var testJson = JsonConvert.SerializeObject(testData, Formatting.Indented); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/ImportExportKeysTest.cs b/SDK/Source/Virgil.SDK.Tests/ImportExportKeysTest.cs deleted file mode 100644 index 43a7782a..00000000 --- a/SDK/Source/Virgil.SDK.Tests/ImportExportKeysTest.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using Virgil.SDK.Cryptography; - using NUnit.Framework; - - public class ImportExportKeysTest - { - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/IntegrationHelper.cs b/SDK/Source/Virgil.SDK.Tests/IntegrationHelper.cs deleted file mode 100644 index 1cad6892..00000000 --- a/SDK/Source/Virgil.SDK.Tests/IntegrationHelper.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System.Configuration; - using System.IO; - using System.Threading.Tasks; - - using Virgil.SDK.Common; - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - - public class IntegrationHelper - { - public static VirgilClient GetVirgilClient() - { - var parameters = new VirgilClientParams(AppAccessToken); - - parameters.SetCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsServicesAddress"]); - parameters.SetReadCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsReadServicesAddress"]); - parameters.SetIdentityServiceAddress(ConfigurationManager.AppSettings["virgil:IdentityServiceAddress"]); - - var client = new VirgilClient(parameters); - - return client; - } - - public static string AppID => ConfigurationManager.AppSettings["virgil:AppID"]; - public static byte[] AppKey => File.ReadAllBytes(ConfigurationManager.AppSettings["virgil:AppKeyPath"]); - public static string AppKeyPath => ConfigurationManager.AppSettings["virgil:AppKeyPath"]; - public static string AppKeyPassword = ConfigurationManager.AppSettings["virgil:AppKeyPassword"]; - public static string AppAccessToken = ConfigurationManager.AppSettings["virgil:AppAccessToken"]; - - public static VirgilApiContext VirgilApiContext() - { - var parameters = new VirgilClientParams(AppAccessToken); - - parameters.SetCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsServicesAddress"]); - parameters.SetReadCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsReadServicesAddress"]); - parameters.SetIdentityServiceAddress(ConfigurationManager.AppSettings["virgil:IdentityServiceAddress"]); - parameters.SetRAServiceAddress(ConfigurationManager.AppSettings["virgil:RAServicesAddress"]); - - return new VirgilApiContext - { - ClientParams = parameters, - Credentials = new AppCredentials - { - AppKey = VirgilBuffer.From(AppKey), - AppKeyPassword = AppKeyPassword, - AppId = AppID - } - }; - } - - public static async Task RevokeCard(string cardId) - { - var client = GetVirgilClient(); - var crypto = new VirgilCrypto(); - var requestSigner = new RequestSigner(crypto); - - var appKey = crypto.ImportPrivateKey(AppKey, AppKeyPassword); - - var revokeRequest = new RevokeCardRequest(cardId, RevocationReason.Unspecified); - requestSigner.AuthoritySign(revokeRequest, AppID, appKey); - - await client.RevokeCardAsync(revokeRequest); - } - - public static string RandomText = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ipsum augue. " + - "Nulla facilisi. Praesent eu laoreet felis. Vivamus scelerisque justo magna, variu" + - "s pharetra augue ultricies non. Vestibulum convallis in urna nec vehicula. Maecen" + - "as mattis suscipit cursus. In iaculis dui ut quam molestie, vel facilisis lacus s" + - "celerisque. Morbi at fermentum felis. Vivamus tincidunt ultricies feugiat. In hac" + - " habitasse platea dictumst. Donec metus diam, luctus et nisi ac, ornare tincidunt" + - " mauris. Fusce posuere lacus non ligula cursus convallis. Proin facilisis ut diam" + - " in cursus. Vivamus in velit a nisi rhoncus vestibulum." + - "Curabitur blandit aliquam ex, et pellentesque elit pharetra at. Donec elementum r" + - "honcus finibus. Duis risus est, porttitor vitae ante vel, sagittis tincidunt veli" + - "In enim ipsum, sagittis at vehicula ut, accumsan nec sapien. Vestibulum conse" + - "ctetur eros a nulla tristique, in lobortis nibh consectetur. Phasellus tincidunt " + - "luctus bibendum. Praesent orci turpis, luctus eget interdum ultricies, vestibulum" + - " a eros. Phasellus sagittis vulputate justo ut condimentum."; - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/KeysGenerationTests.cs b/SDK/Source/Virgil.SDK.Tests/KeysGenerationTests.cs deleted file mode 100644 index 0a6787ad..00000000 --- a/SDK/Source/Virgil.SDK.Tests/KeysGenerationTests.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Virgil.SDK.Tests -{ - public class KeysGenerationTests - { - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/PrivateKeyStorageTests.cs b/SDK/Source/Virgil.SDK.Tests/PrivateKeyStorageTests.cs new file mode 100644 index 00000000..0876873b --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests/PrivateKeyStorageTests.cs @@ -0,0 +1,38 @@ +using Bogus; +using NUnit.Framework; +using System; +using Virgil.CryptoImpl; +using Virgil.SDK.Storage; + +namespace Virgil.SDK.Tests.Shared +{ + [NUnit.Framework.TestFixture] + public class PrivateKeyStorageTestsNet + { + private readonly Faker faker = new Faker(); + + [Test] + public void Load_Should_Return_EqualOldPrivateKey_If_StorageHasSHA256Exporter() + { + var exporterPass = faker.Random.AlphaNumeric(10); + var storagePass = faker.Random.AlphaNumeric(10); + var crypto = new VirgilCrypto(); + var cryptoSHA256 = new VirgilCrypto() { UseSHA256Fingerprints = true }; + + var exporter = new VirgilPrivateKeyExporter(cryptoSHA256, exporterPass); + var privateKeyStorage = new PrivateKeyStorage(exporter, storagePass); + + var storageReader = + new KeyStorageReaderV4(AppSettings.OldKeyStoragePath, true); + var (oldKeyData, oldKeydata) = storageReader.Load(AppSettings.OldKeyAliase); + var key = cryptoSHA256.ImportPrivateKey(oldKeyData); + var oldKeyAliase = faker.Random.AlphaNumeric(10); + privateKeyStorage.Store(key, oldKeyAliase); + var loadedOldKey = privateKeyStorage.Load(oldKeyAliase).Item1; + + //Assert.IsTrue(((PrivateKey)key).Id.SequenceEqual(((PrivateKey)loadedOldKey).Id)); + //Assert.IsTrue(((PrivateKey)key).RawKey.SequenceEqual(((PrivateKey)loadedOldKey).RawKey)); + privateKeyStorage.Delete(oldKeyAliase); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.SDK.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index bb79affd..00000000 --- a/SDK/Source/Virgil.SDK.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Virgil.SDK.Keys.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Virgil.SDK.Keys.Tests")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0dae4d07-3749-4eec-986e-5157d39e35a1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// 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("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SDK/Source/Virgil.SDK.Tests/RelationTests.cs b/SDK/Source/Virgil.SDK.Tests/RelationTests.cs deleted file mode 100644 index 479c6990..00000000 --- a/SDK/Source/Virgil.SDK.Tests/RelationTests.cs +++ /dev/null @@ -1,157 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using Client; - using Common; - using Cryptography; - using NUnit.Framework; - using System.Configuration; - using System.Threading.Tasks; - using System.Collections.Generic; - using System.Linq; - using FluentAssertions; - - - public class RelationTests - { - [Test] - public async Task AddOrDeleteRelation_ShouldAddOrDeleteEntryINRelations() - { - const string identityType = "member"; - var crypto = new VirgilCrypto(); - var client = PredefinedClient(crypto); - var requestSigner = new RequestSigner(crypto); - - var aliceKeys = crypto.GenerateKeys(); - var aliceExportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - var aliceRequest = new PublishCardRequest("alice", identityType, aliceExportedPublicKey); - - var bobKeys = crypto.GenerateKeys(); - var bobExportedPublicKey = crypto.ExportPublicKey(bobKeys.PublicKey); - var bobRequest = new PublishCardRequest("bob", identityType, bobExportedPublicKey); - - var appId = ConfigurationManager.AppSettings["virgil:AppID"]; - var appKey = crypto.ImportPrivateKey( - VirgilBuffer.FromFile(ConfigurationManager.AppSettings["virgil:AppKeyPath"]).GetBytes(), - ConfigurationManager.AppSettings["virgil:AppKeyPassword"]); - - - // publish cards - requestSigner.SelfSign(aliceRequest, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(aliceRequest, appId, appKey); - var aliceCardModel = await client - .PublishCardAsync(aliceRequest).ConfigureAwait(false); - - requestSigner.SelfSign(bobRequest, bobKeys.PrivateKey); - requestSigner.AuthoritySign(bobRequest, appId, appKey); - var bobCardModel = await client - .PublishCardAsync(bobRequest).ConfigureAwait(false); - - aliceCardModel.Meta.Relations.Count.ShouldBeEquivalentTo(0); - - // add Bob's card to Alice's relations - var addRelationRequest = new AddRelationRequest(bobCardModel.SnapshotModel); - requestSigner.AuthoritySign(addRelationRequest, aliceCardModel.Id, aliceKeys.PrivateKey); - var aliceCardModelWithRelation = await client.AddRelationAsync(addRelationRequest); - - aliceCardModelWithRelation.Meta.Relations.Count.ShouldBeEquivalentTo(1); - var relationKey = aliceCardModelWithRelation.Meta.Relations.Keys.First(); - relationKey.ShouldBeEquivalentTo(bobCardModel.Id); - - //Delete Bob's card from Alice's relations - var deleteRelationRequest = new DeleteRelationRequest(bobCardModel.Id, RevocationReason.Unspecified); - requestSigner.AuthoritySign(deleteRelationRequest, aliceCardModelWithRelation.Id, aliceKeys.PrivateKey); - - var aliceCardModelWithoutRelation = await client.DeleteRelationAsync(deleteRelationRequest); - aliceCardModelWithoutRelation.Meta.Relations.Count.ShouldBeEquivalentTo(0); - - // delete cards - var revokeBobRequest = new RevokeCardRequest(bobCardModel.Id, RevocationReason.Unspecified); - requestSigner.AuthoritySign(revokeBobRequest, appId, appKey); - await client.RevokeCardAsync(revokeBobRequest); - - var revokeAliceRequest = new RevokeCardRequest(aliceCardModel.Id, RevocationReason.Unspecified); - requestSigner.AuthoritySign(revokeAliceRequest, appId, appKey); - await client.RevokeCardAsync(revokeAliceRequest); - } - - [Test] - public async Task AddOrDeleteRelationWithoutAuthoritySign_ExceptionShouldOccur() - { - - const string identityType = "member"; - var crypto = new VirgilCrypto(); - var client = PredefinedClient(crypto); - var requestSigner = new RequestSigner(crypto); - - var aliceKeys = crypto.GenerateKeys(); - var aliceExportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - var aliceRequest = new PublishCardRequest("alice", identityType, aliceExportedPublicKey); - - var bobKeys = crypto.GenerateKeys(); - var bobExportedPublicKey = crypto.ExportPublicKey(bobKeys.PublicKey); - var bobRequest = new PublishCardRequest("bob", identityType, bobExportedPublicKey); - - var appId = ConfigurationManager.AppSettings["virgil:AppID"]; - var appKey = crypto.ImportPrivateKey( - VirgilBuffer.FromFile(ConfigurationManager.AppSettings["virgil:AppKeyPath"]).GetBytes(), - ConfigurationManager.AppSettings["virgil:AppKeyPassword"]); - - - // publish cards - requestSigner.SelfSign(aliceRequest, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(aliceRequest, appId, appKey); - var aliceCardModel = await client - .PublishCardAsync(aliceRequest).ConfigureAwait(false); - - requestSigner.SelfSign(bobRequest, bobKeys.PrivateKey); - requestSigner.AuthoritySign(bobRequest, appId, appKey); - var bobCardModel = await client - .PublishCardAsync(bobRequest).ConfigureAwait(false); - - aliceCardModel.Meta.Relations.Count.ShouldBeEquivalentTo(0); - - - // add Bob's card to Alice's relations - var addRelationRequest = new AddRelationRequest(bobCardModel.SnapshotModel); - Assert.ThrowsAsync(() => client.AddRelationAsync(addRelationRequest)); - - // Delete Bob's card from Alice's relations - var deleteRelationRequest = new DeleteRelationRequest(bobCardModel.Id, RevocationReason.Unspecified); - Assert.ThrowsAsync(() => client.DeleteRelationAsync(deleteRelationRequest)); - - // delete cards - var revokeBobRequest = new RevokeCardRequest(bobCardModel.Id, RevocationReason.Unspecified); - requestSigner.AuthoritySign(revokeBobRequest, appId, appKey); - await client.RevokeCardAsync(revokeBobRequest); - - var revokeAliceRequest = new RevokeCardRequest(aliceCardModel.Id, RevocationReason.Unspecified); - requestSigner.AuthoritySign(revokeAliceRequest, appId, appKey); - await client.RevokeCardAsync(revokeAliceRequest); - } - - private VirgilClient PredefinedClient(VirgilCrypto crypto) - { - var clientParams = new VirgilClientParams(ConfigurationManager.AppSettings["virgil:AppAccessToken"]); - clientParams.SetCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsServicesAddress"]); - clientParams.SetIdentityServiceAddress(ConfigurationManager.AppSettings["virgil:IdentityServiceAddress"]); - clientParams.SetRAServiceAddress(ConfigurationManager.AppSettings["virgil:RAServicesAddress"]); - clientParams.SetReadCardsServiceAddress(ConfigurationManager.AppSettings["virgil:CardsReadServicesAddress"]); - - var validator = new CardValidator(crypto); - - // To use staging Verifier instead of default verifier - var cardVerifier = new CardVerifierInfo - { - CardId = ConfigurationManager.AppSettings["virgil:ServiceCardId"], - PublicKeyData = VirgilBuffer.From(ConfigurationManager.AppSettings["virgil:ServicePublicKeyDerBase64"], - StringEncoding.Base64) - }; - validator.AddVerifier(cardVerifier.CardId, cardVerifier.PublicKeyData.GetBytes()); - - var client = new VirgilClient(clientParams); - client.SetCardValidator(validator); - - return client; - } - } -} diff --git a/SDK/Source/Virgil.SDK.Tests/SecureStorageTests.cs b/SDK/Source/Virgil.SDK.Tests/SecureStorageTests.cs new file mode 100644 index 00000000..8b914ae1 --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests/SecureStorageTests.cs @@ -0,0 +1,124 @@ +using System.Collections.Generic; +using System.Linq; +using Bogus; +using NUnit.Framework; +using Virgil.SDK.Exceptions; + +namespace Virgil.SDK.Tests +{ + + [TestFixture] + public class SecureStorageTests + { + private readonly Faker faker = new Faker(); + + [SetUp] + public void SetUp() + { + SecureStorage.StorageIdentity = "Virgil.SecureStorage.Tests6"; + } + + [Test] + public void Save_Should_SaveDataUnderKey() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storedData = storage.Load(key); + Assert.IsTrue(storedData.SequenceEqual(data)); + storage.Delete(key); + } + + [Test] + public void Save_Should_SaveDataBetweenSessions() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + var storage2 = new SecureStorage(passw); + + var storedData = storage2.Load(key); + Assert.IsTrue(storedData.SequenceEqual(data)); + storage.Delete(key); + } + + [Test] + public void SaveWithDuplicateKey_Should_RaiseDuplicateKeyException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = faker.Person.UserName; + + storage.Save(key, data); + Assert.Throws( + () => storage.Save(key, data)); + storage.Delete(key); + } + + [Test] + public void LoadByMissingKey_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + + Assert.Throws( + () => storage.Load(key)); + } + + [Test] + public void DeleteByMissingKey_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + Assert.Throws( + () => storage.Delete(key)); + } + + [Test] + public void Keys_Should_ReturnAllSavedKeys() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var data = faker.Random.Bytes(32); + var key = "my_key_11"; + var key2 = "my_key_22"; + + //var key3 = "dd\\lllll\\aaa"; + storage.Save(key, data); + storage.Save(key2, data); + //storage.Save(key3, data); + var keys = storage.Aliases(); + Assert.AreEqual(keys.Length, 2); + Assert.IsTrue(keys.Contains(key)); + Assert.IsTrue(keys.Contains(key2)); + + storage.Delete(key); + storage.Delete(key2); + } + + [Test] + public void LoadByWrongPass_Should_RaiseKeyNotFoundException() + { + var passw = faker.Random.Words(); + var storage = new SecureStorage(passw); + var key = faker.Person.UserName; + var data = faker.Random.Bytes(32); + storage.Save(key, data); + //change pass + var passw2 = faker.Random.Words(); + var storage2 = new SecureStorage(passw2); + Assert.Throws( + () => storage2.Load(key)); + storage.Delete(key); + } + } +} diff --git a/SDK/Source/Virgil.SDK.Tests/TestHelper.cs b/SDK/Source/Virgil.SDK.Tests/TestHelper.cs new file mode 100644 index 00000000..b381c7ee --- /dev/null +++ b/SDK/Source/Virgil.SDK.Tests/TestHelper.cs @@ -0,0 +1,4 @@ +namespace Virgil.SDK.Tests +{ + +} diff --git a/SDK/Source/Virgil.SDK.Tests/Tools/GenerateForMe.cs b/SDK/Source/Virgil.SDK.Tests/Tools/GenerateForMe.cs deleted file mode 100644 index 28e3fb70..00000000 --- a/SDK/Source/Virgil.SDK.Tests/Tools/GenerateForMe.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Virgil.SDK.Tests.Tools -{ - using System; - - public class GenerateMe - { - public static byte[] RandomBytes(int min = 100, int max = 1000) - { - var random = new Random(); - - var randomCount = random.Next(min, max); - var randomBytes = new byte[randomCount]; - - random.NextBytes(randomBytes); - - return randomBytes; - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/Virgil.SDK.Tests.csproj b/SDK/Source/Virgil.SDK.Tests/Virgil.SDK.Tests.csproj index f02ac31b..683ed8dc 100644 --- a/SDK/Source/Virgil.SDK.Tests/Virgil.SDK.Tests.csproj +++ b/SDK/Source/Virgil.SDK.Tests/Virgil.SDK.Tests.csproj @@ -1,136 +1,128 @@  - - + + + Debug AnyCPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD} + {5718132F-B918-41C8-9FDC-589DF0DFB7A6} Library - Properties Virgil.SDK.Tests Virgil.SDK.Tests - v4.5 - 512 + v4.7.1 + - ..\ - true true full false - bin\Debug\ - DEBUG;TRACE + bin\Debug + DEBUG; prompt 4 - pdbonly + + true - bin\Release\ - TRACE + bin\Release prompt 4 - - ..\packages\NBuilder.3.0.1.1\lib\FizzWare.NBuilder.dll - True + + + ..\packages\Microsoft.CodeCoverage.1.0.3\lib\netstandard1.0\Microsoft.VisualStudio.CodeCoverage.Shim.dll - - ..\packages\FluentAssertions.4.12.0\lib\net45\FluentAssertions.dll - True + + ..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll - - ..\packages\FluentAssertions.4.12.0\lib\net45\FluentAssertions.Core.dll - True + + ..\packages\PCLAppConfig.0.3.4\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\PCLAppConfig.dll - - ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - True + + ..\packages\PCLAppConfig.0.3.4\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\PCLAppConfig.FileSystemStream.dll - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\packages\PCLAppConfig.0.3.4\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\PCLAppConfig.FileSystemStream.Abstractions.dll - - ..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll - True + + ..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.dll - - ..\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll - True + + ..\packages\PCLStorage.1.0.2\lib\net45\PCLStorage.Abstractions.dll - - - - - - + - - ..\packages\Virgil.Crypto.2.1.2\lib\portable-net4+sl4+wp7+win8+wpa81\Virgil.Crypto.dll + + + + + ..\packages\Bogus.20.0.2\lib\net40\Bogus.dll + + + ..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll + + + ..\packages\NBuilder.5.0.0\lib\net40\FizzWare.NBuilder.dll + + + ..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll + + + ..\packages\NSubstitute.3.1.0\lib\net46\NSubstitute.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + ..\packages\Virgil.Crypto.2.3.0\lib\net45\Virgil.Crypto.dll + + + ..\packages\Virgil.CryptoAPI.1.0.0\lib\portable-net45+win+wpa81+MonoTouch10+xamarinmac20\Virgil.CryptoApi.dll + + + ..\packages\Virgil.CryptoImpl.1.0.1\lib\net45\Virgil.CryptoImpl.dll - - - - - - - - - - - - - - - - - - + + Designer + + + + + - - - Designer - + - - {6a795ff4-e64b-4770-a50f-329a7d77f618} - Virgil.SDK.Contracts - + + + - {e597b732-df22-4899-b27b-4c47aac4ee3f} + {724be592-c519-4490-9057-f62f3b2fee2c} Virgil.SDK.NetFx - - - - + + + + + - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/VirgilBufferTests.cs b/SDK/Source/Virgil.SDK.Tests/VirgilBufferTests.cs deleted file mode 100644 index 3eef9f07..00000000 --- a/SDK/Source/Virgil.SDK.Tests/VirgilBufferTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Text; - using FluentAssertions; - using NUnit.Framework; - - using Virgil.SDK.Tests.Tools; - - public class VirgilBufferTests - { - [Test] - public void Ctor_EmptyByteArrayGiven_ShouldThrowException() - { - var bytes = new byte[0]; - Assert.Throws(() => new VirgilBuffer(bytes)); - } - - [Test] - public void Ctor_NullByteArrayGiven_ShouldThrowException() - { - Assert.Throws(() => new VirgilBuffer(null)); - } - - [Test] - public void ToBase64String_InstantiatedWithRandomBytes_ShouldReturnBase64EncodedString() - { - var randomBytes = GenerateMe.RandomBytes(); - - var buffer = new VirgilBuffer(randomBytes); - var resultString = buffer.ToString(StringEncoding.Base64); - - resultString.Should().Be(Convert.ToBase64String(randomBytes)); - } - - [Test] - public void ToUtf8String_InstantiatedWithRandomBytes_ShouldReturnUtf8String() - { - var randomBytes = GenerateMe.RandomBytes(); - - var buffer = new VirgilBuffer(randomBytes); - var resultString = buffer.ToString(); - - resultString.Should().Be(Encoding.UTF8.GetString(randomBytes)); - } - - [Test] - public void ToHEXString_InstantiatedWithRandomBytes_ShouldReturnNotSeporatedLovercaseHexString() - { - var randomBytes = GenerateMe.RandomBytes(); - - var buffer = new VirgilBuffer(randomBytes); - var resultString = buffer.ToString(StringEncoding.Hex); - - resultString.Should().Be(BitConverter.ToString(randomBytes).Replace("-", "").ToLower()); - } - - [Test] - public void GetBytes_InstantiatedWithRandomBytes_ShouldReturnTheSameBytesAsInitialized() - { - var randomBytes = GenerateMe.RandomBytes(); - - var buffer = new VirgilBuffer(randomBytes); - var resultString = buffer.GetBytes(); - - Assert.AreEqual(resultString, randomBytes); - } - } -}; \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/VirgilCardCreationTest.cs b/SDK/Source/Virgil.SDK.Tests/VirgilCardCreationTest.cs deleted file mode 100644 index acce3b6c..00000000 --- a/SDK/Source/Virgil.SDK.Tests/VirgilCardCreationTest.cs +++ /dev/null @@ -1,107 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Linq; - using System.Threading.Tasks; - using Common; - using FluentAssertions; - - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - - using NUnit.Framework; - using Virgil.SDK.Exceptions; - using System.Collections.Generic; - - public class VirgilCardCreationTest - { - [Test] - public async Task CreateNewVirgilCard_DuplicateCardCreation_ShouldThrowException() - { - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var aliceIdentity = "alice-" + Guid.NewGuid(); - var request = new PublishCardRequest(aliceIdentity, "member", exportedPublicKey); - - var requestSigner = new RequestSigner(crypto); - - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(request, IntegrationHelper.AppID, appKey); - - var virgilCard = await client.PublishCardAsync(request); - Assert.ThrowsAsync(async () => await client.PublishCardAsync(request)); - } - - [Test] - public async Task CreateNewVirgilCard_IdentityAndPublicKeyGiven_ShouldBeFoundByIdentity() - { - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var aliceIdentity = "alice-" + Guid.NewGuid(); - - var request = new PublishCardRequest(aliceIdentity, "member", exportedPublicKey); - - var requestSigner = new RequestSigner(crypto); - - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(request, IntegrationHelper.AppID, appKey); - - var newCard = await client.PublishCardAsync(request); - var cards = await client.SearchCardsAsync(new SearchCriteria { Identities = new[] { aliceIdentity } }); - - cards.Should().HaveCount(1); - var foundCard = cards.Single(); - - newCard.ShouldBeEquivalentTo(foundCard); - } - - [Test] - public async Task CreateNewVirgilCard_SignatureValidation_ShouldPassValidation() - { - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - - // CREATING A VIRGIL CARD - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var aliceIdentity = "alice-" + Guid.NewGuid(); - var request = new PublishCardRequest(aliceIdentity, "member", exportedPublicKey); - - var requestSigner = new RequestSigner(crypto); - - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(request, IntegrationHelper.AppID, appKey); - - var aliceCard = await client.PublishCardAsync(request); - - // VALIDATING A VIRGIL CARD - - var appPublicKey = crypto.ExtractPublicKey(appKey); - var exportedAppPublicKey = crypto.ExportPublicKey(appPublicKey); - - var validator = new CardValidator(crypto); - validator.AddVerifier(IntegrationHelper.AppID, exportedAppPublicKey); - - validator.Validate(aliceCard).Should().BeTrue(); - - await IntegrationHelper.RevokeCard(aliceCard.Id); - } - - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/VirgilCardSearchTest.cs b/SDK/Source/Virgil.SDK.Tests/VirgilCardSearchTest.cs deleted file mode 100644 index 1a7af7a4..00000000 --- a/SDK/Source/Virgil.SDK.Tests/VirgilCardSearchTest.cs +++ /dev/null @@ -1,129 +0,0 @@ -namespace Virgil.SDK.Tests -{ - using System; - using System.Linq; - using System.Threading.Tasks; - using FluentAssertions; - using NUnit.Framework; - - using Virgil.SDK.Common; - using Virgil.SDK.Client; - using Virgil.SDK.Cryptography; - - public class VirgilCardSearchTest - { - [Test] - public async Task SearchForVirgilCards_ValidationWithServiceKey_ShouldPassValidation() - { - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - client.SetCardValidator(new CardValidator(crypto)); - - // CREATING A VIRGIL CARD - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - var aliceKeys = crypto.GenerateKeys(); - var exportedPublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var aliceIdentity = "alice-" + Guid.NewGuid(); - var request = new PublishCardRequest(aliceIdentity, "member", exportedPublicKey); - - var requestSigner = new RequestSigner(crypto); - - requestSigner.SelfSign(request, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(request, IntegrationHelper.AppID, appKey); - - var aliceCard = await client.PublishCardAsync(request); - - // VALIDATING A VIRGIL CARD - - var cards = await client.SearchCardsAsync(SearchCriteria.ByIdentity(aliceIdentity)); - - aliceCard.ShouldBeEquivalentTo(cards.Single()); - - await IntegrationHelper.RevokeCard(aliceCard.Id); - } - - [Test] - public async Task SearchForTheVirgilCards_MultipleIdentitiesGiven_ShouldReturnVirgilCards() - { - // Initialization - - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - var requestSigner = new RequestSigner(crypto); - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - // Prepare Requests - - var aliceIdentity = "alice-" + Guid.NewGuid(); - var aliceKeys = crypto.GenerateKeys(); - var alicePublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var bobIdentity = "bob-" + Guid.NewGuid(); - var bobKeys = crypto.GenerateKeys(); - var bobPublicKey = crypto.ExportPublicKey(bobKeys.PublicKey); - - var aliceRequest = new PublishCardRequest(aliceIdentity, "member", alicePublicKey); - var bobRequest = new PublishCardRequest(bobIdentity, "member", bobPublicKey); - - requestSigner.SelfSign(aliceRequest, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(aliceRequest, IntegrationHelper.AppID, appKey); - - requestSigner.SelfSign(bobRequest, bobKeys.PrivateKey); - requestSigner.AuthoritySign(bobRequest, IntegrationHelper.AppID, appKey); - - // Publish Virgil Cards - - var aliceCard = await client.PublishCardAsync(aliceRequest); - var bobCard = await client.PublishCardAsync(bobRequest); - - // Search for the Virgil Cards - - var foundCards = await client.SearchCardsAsync(new SearchCriteria - { - Identities = new[] { bobIdentity, aliceIdentity } - }); - - // Assertions - - foundCards.Should().HaveCount(2); - - foundCards.Single(it => it.Id == aliceCard.Id).ShouldBeEquivalentTo(aliceCard); - foundCards.Single(it => it.Id == bobCard.Id).ShouldBeEquivalentTo(bobCard); - - await IntegrationHelper.RevokeCard(aliceCard.Id); - await IntegrationHelper.RevokeCard(bobCard.Id); - } - - [Test] - public async Task GetSignleVirgilCard_ByGivenId_ShouldReturnVirgilCard() - { - var crypto = new VirgilCrypto(); - var client = IntegrationHelper.GetVirgilClient(); - var requestSigner = new RequestSigner(crypto); - - var appKey = crypto.ImportPrivateKey(IntegrationHelper.AppKey, IntegrationHelper.AppKeyPassword); - - // Prepare Requests - - var aliceIdentity = "alice-" + Guid.NewGuid(); - var aliceKeys = crypto.GenerateKeys(); - var alicePublicKey = crypto.ExportPublicKey(aliceKeys.PublicKey); - - var aliceRequest = new PublishCardRequest(aliceIdentity, "member", alicePublicKey); - - requestSigner.SelfSign(aliceRequest, aliceKeys.PrivateKey); - requestSigner.AuthoritySign(aliceRequest, IntegrationHelper.AppID, appKey); - - var aliceCard = await client.PublishCardAsync(aliceRequest); - var foundAliceCard = await client.GetCardAsync(aliceCard.Id); - - aliceCard.ShouldBeEquivalentTo(foundAliceCard); - - await IntegrationHelper.RevokeCard(aliceCard.Id); - } - } -} \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.Tests/app.virgilkey.enc b/SDK/Source/Virgil.SDK.Tests/app.virgilkey.enc deleted file mode 100644 index f9be82b8..00000000 Binary files a/SDK/Source/Virgil.SDK.Tests/app.virgilkey.enc and /dev/null differ diff --git a/SDK/Source/Virgil.SDK.Tests/packages.config b/SDK/Source/Virgil.SDK.Tests/packages.config index 4238ac80..5849af7f 100644 --- a/SDK/Source/Virgil.SDK.Tests/packages.config +++ b/SDK/Source/Virgil.SDK.Tests/packages.config @@ -1,10 +1,25 @@  - - - - - - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeyException.cs b/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeyException.cs new file mode 100644 index 00000000..c9a08be2 --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeyException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when an key already exists. + /// + public class DuplicateKeyException : SecureStorageException + { + public DuplicateKeyException(string key) + : base($"Specified key '{key}' is already exists in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeySecureStorageException.cs b/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeySecureStorageException.cs new file mode 100644 index 00000000..4962c737 --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/Exceptions/DuplicateKeySecureStorageException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when an key already exists. + /// + public class DuplicateKeySecureStorageException : SecureStorageException + { + public DuplicateKeySecureStorageException(string key) + : base($"Specified key '{key}' is already exists in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundException.cs b/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundException.cs new file mode 100644 index 00000000..03f6e5fe --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when the key doesn't exist. + /// + public class KeyNotFoundException : SecureStorageException + { + public KeyNotFoundException(string key) + : base($"Specified key '{key}' doesn't exist in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundSecureStorageException.cs b/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundSecureStorageException.cs new file mode 100644 index 00000000..15e73a41 --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/Exceptions/KeyNotFoundSecureStorageException.cs @@ -0,0 +1,13 @@ +namespace Virgil.SDK.Storage.Exceptions +{ + /// + /// The exception that is thrown when the key doesn't exist. + /// + public class KeyNotFoundSecureStorageException : SecureStorageException + { + public KeyNotFoundSecureStorageException(string key) + : base($"Specified key '{key}' doesn't exist in the secure storage.") + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Exceptions/SecureStorageException.cs b/SDK/Source/Virgil.SDK.iOS/Exceptions/SecureStorageException.cs new file mode 100644 index 00000000..c0ba2a49 --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/Exceptions/SecureStorageException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Virgil.SDK.Storage.Exceptions +{ + public class SecureStorageException : Exception + { + public SecureStorageException(string message) : base(message) + { + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Native References/libVirgilCryptoNet.a b/SDK/Source/Virgil.SDK.iOS/Native References/libVirgilCryptoNet.a new file mode 100644 index 00000000..8fe9e7b5 Binary files /dev/null and b/SDK/Source/Virgil.SDK.iOS/Native References/libVirgilCryptoNet.a differ diff --git a/SDK/Source/Virgil.SDK.iOS/Properties/AssemblyInfo.cs b/SDK/Source/Virgil.SDK.iOS/Properties/AssemblyInfo.cs index 23e5e69f..f7840a40 100644 --- a/SDK/Source/Virgil.SDK.iOS/Properties/AssemblyInfo.cs +++ b/SDK/Source/Virgil.SDK.iOS/Properties/AssemblyInfo.cs @@ -5,14 +5,15 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Virgil.SDK.iOS")] +[assembly: AssemblyTitle("Virgil.SDK")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Virgil.SDK.iOS")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyProduct("Virgil.SDK")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +[assembly: InternalsVisibleTo("Virgil.SDK.Tests")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from @@ -33,4 +34,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.iOS/SecureStorage.cs b/SDK/Source/Virgil.SDK.iOS/SecureStorage.cs new file mode 100644 index 00000000..93c1dc2f --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/SecureStorage.cs @@ -0,0 +1,159 @@ +using System; +using Foundation; +using Security; +using Virgil.SDK.Storage; +using Virgil.SDK.Storage.Exceptions; + +namespace Virgil.SDK.Storage +{ + /// + /// This class implements a secure storage for cryptographic keys. + /// + public class SecureStorage + { + /// + /// Storage identity + /// + public static string StorageIdentity = "Virgil.SecureStorage"; + + /// + /// Constructor + /// + public SecureStorage() + { + if (string.IsNullOrWhiteSpace(StorageIdentity)) + { + throw new SecureStorageException("StorageIdentity can't be empty"); + } + } + + /// + /// Stores the key data to the given alias. + /// + /// The alias. + /// The key data. + /// + public void Save(string alias, byte[] data) + { + this.ValidateAlias(alias); + this.ValidateData(data); + + if (this.Exists(alias)) + { + throw new DuplicateKeySecureStorageException(alias); + } + var record = NewSecRecord(alias, data); + var result = SecKeyChain.Add(record); + if (result != SecStatusCode.Success) + { + throw new SecureStorageException($"The key under alias '{alias}' can't be saved."); + }; + } + + /// + /// Checks if the key data exists in this storage by given alias. + /// + /// The alias. + /// true if the key data exists, false otherwise + public bool Exists(string alias) + { + this.ValidateAlias(alias); + + return (this.FindRecord(alias).Item1 == SecStatusCode.Success); + } + + /// + /// Loads the key data associated with the given alias. + /// + /// The alias. + /// + /// The requested data, or exception if the given key does not exist. + /// + /// + public byte[] Load(string alias) + { + this.ValidateAlias(alias); + + (var secStatusCode, var foundSecRecord) = this.FindRecord(alias); + if (secStatusCode == SecStatusCode.Success) + { + return foundSecRecord.ValueData.ToArray(); + } + + throw new KeyNotFoundSecureStorageException(alias); + } + + /// + /// Delete key data by the alias in this storage. + /// + /// The alias. + /// + public void Delete(string alias) + { + this.ValidateAlias(alias); + + (var secStatusCode, var foundSecRecord) = this.FindRecord(alias); + if (secStatusCode != SecStatusCode.Success) + { + throw new KeyNotFoundSecureStorageException(alias); + } + var secRecord = NewSecRecord(alias, null); + SecKeyChain.Remove(secRecord); + } + + /// + /// Returns the list of aliases + /// + public string[] Aliases() + { + // all labels at the Virgil storage + var secRecord = new SecRecord(SecKind.GenericPassword) { Service = StorageIdentity }; + var foundSecRecords = SecKeyChain.QueryAsRecord(secRecord, 100, out var secStatusCode); + var aliases = new string[foundSecRecords.Length]; + + for (var i = 0; i < foundSecRecords.Length; i++) + { + aliases[i] = foundSecRecords[i].Label; + } + return aliases; + } + + private Tuple FindRecord(string alias) + { + var secRecord = NewSecRecord(alias, null); + var found = SecKeyChain.QueryAsRecord(secRecord, out var secStatusCode); + return new Tuple(secStatusCode, found); + } + + private SecRecord NewSecRecord(string alias, byte[] data) + { + var secRecord = new SecRecord(SecKind.GenericPassword) + { + Account = alias, + Service = StorageIdentity, + Label = alias + }; + if (data != null && data.Length > 0) + { + secRecord.ValueData = NSData.FromArray(data); + } + return secRecord; + } + + private void ValidateAlias(string alias) + { + if (string.IsNullOrWhiteSpace(alias)) + { + throw new ArgumentException($"{nameof(alias)} can't be empty."); + } + } + + private void ValidateData(byte[] data) + { + if (data == null || data.Length == 0) + { + throw new ArgumentException($"{nameof(data)} can't be empty."); + } + } + } +} diff --git a/SDK/Source/Virgil.SDK.iOS/Virgil.SDK.iOS.csproj b/SDK/Source/Virgil.SDK.iOS/Virgil.SDK.iOS.csproj index 63ff6cbf..e574373e 100644 --- a/SDK/Source/Virgil.SDK.iOS/Virgil.SDK.iOS.csproj +++ b/SDK/Source/Virgil.SDK.iOS/Virgil.SDK.iOS.csproj @@ -11,6 +11,8 @@ Virgil.SDK Resources Virgil.SDK.iOS + + true @@ -23,7 +25,7 @@ false - full + true bin\Release prompt @@ -35,13 +37,37 @@ + + + + + ..\packages\Newtonsoft.Json.10.0.3\lib\netstandard1.3\Newtonsoft.Json.dll + + + - + + + + + + + - + + + + + + + + + {BCC9EB08-9768-413E-A69D-FE45699F213D} + Virgil.CryptoAPI + - + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.iOS/packages.config b/SDK/Source/Virgil.SDK.iOS/packages.config new file mode 100644 index 00000000..babcea71 --- /dev/null +++ b/SDK/Source/Virgil.SDK.iOS/packages.config @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.nuspec b/SDK/Source/Virgil.SDK.nuspec new file mode 100644 index 00000000..d853ce58 --- /dev/null +++ b/SDK/Source/Virgil.SDK.nuspec @@ -0,0 +1,38 @@ + + + + Virgil.SDK + 1.0.0 + Virgil.SDK + Virgil Security, Inc + Virgil Security, Inc + + + + Virgil.CryptoImpl provides implementation of Virgil.CryptoAPI interfaces using Virgil.Crypto library. + + + Virgil Security allows to identify users in your digital solutions. Create users Virgil Cards with Public Keys inside and use Public Key Management to protect data. + + Docs - https://developer.virgilsecurity.com/docs/how-to#sdk-configuration + Source - https://github.com/VirgilSecurity/virgil-sdk-net + + Supported Platforms: + - .NET Framework 4.6.0+ + - ASP.NET Core 1.0+ + - Windows 8+ + - Windows Phone 8.1+ + - Windows Phone Silverlight 8+ + + en-US + https://virgilsecurity.com/ + https://avatars0.githubusercontent.com/u/9740508 + false + http://opensource.org/licenses/Apache-2.0 + © 2018 Virgil Security, Inc. + + + + virgil, encryption, crypto, cryptography + + \ No newline at end of file diff --git a/SDK/Source/Virgil.SDK.sln b/SDK/Source/Virgil.SDK.sln index 34227ce9..e42b9d25 100644 --- a/SDK/Source/Virgil.SDK.sln +++ b/SDK/Source/Virgil.SDK.sln @@ -1,227 +1,403 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2020 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests", "Virgil.SDK.Tests\Virgil.SDK.Tests.csproj", "{9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platforms", "Platforms", "{253019A0-C549-4F24-A7A4-E5E0FA4E4591}" EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Virgil.SDK.Shared", "Virgil.SDK.Shared\Virgil.SDK.Shared.shproj", "{6E4FE86F-7862-4FD9-B2E3-B73AE0957EB6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Droid", "Virgil.SDK.Droid\Virgil.SDK.Droid.csproj", "{6B9CE116-871B-4294-AA8E-64DE316AA79A}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Virgil.SDK.Tests.Shared", "Virgil.SDK.Tests.Shared\Virgil.SDK.Tests.Shared.shproj", "{3D15E8EB-42FE-4756-93E1-506C28E48612}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.iOS", "Virgil.SDK.iOS\Virgil.SDK.iOS.csproj", "{DB5F3E5D-83FD-48BC-8842-95AA70A27928}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.NetFx", "Virgil.SDK.NetFx\Virgil.SDK.NetFx.csproj", "{E597B732-DF22-4899-B27B-4C47AAC4EE3F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests.iOS", "Virgil.SDK.Tests.iOS\Virgil.SDK.Tests.iOS.csproj", "{095DE394-7344-4487-BF42-386B85C730EB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platforms", "Platforms", "{253019A0-C549-4F24-A7A4-E5E0FA4E4591}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests", "Virgil.SDK.Tests\Virgil.SDK.Tests.csproj", "{5718132F-B918-41C8-9FDC-589DF0DFB7A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests.Mac", "Virgil.SDK.Tests.Mac\Virgil.SDK.Tests.Mac.csproj", "{2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests.Droid", "Virgil.SDK.Tests.Droid\Virgil.SDK.Tests.Droid.csproj", "{0FA9B741-3F82-4965-92C7-9E0895E80E5A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Droid", "Virgil.SDK.Droid\Virgil.SDK.Droid.csproj", "{6B9CE116-871B-4294-AA8E-64DE316AA79A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Contracts", "Virgil.SDK.Contracts\Virgil.SDK.Contracts.csproj", "{6A795FF4-E64B-4770-A50F-329A7D77F618}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Mac", "Virgil.SDK.Mac\Virgil.SDK.Mac.csproj", "{801B62A3-AE2E-48E2-B9CD-F9F5C469048C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.Tests.Mac2", "Virgil.SDK.Tests.Mac2\Virgil.SDK.Tests.Mac2.csproj", "{2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virgil.SDK.NetFx", "Virgil.SDK.NetFx\Virgil.SDK.NetFx.csproj", "{724BE592-C519-4490-9057-F62F3B2FEE2C}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - Virgil.SDK.Shared\Virgil.SDK.Shared.projitems*{6b9ce116-871b-4294-aa8e-64de316aa79a}*SharedItemsImports = 4 + Virgil.SDK.Tests.Shared\Virgil.SDK.Tests.Shared.projitems*{3d15e8eb-42fe-4756-93e1-506c28e48612}*SharedItemsImports = 13 + Virgil.SDK.Shared\Virgil.SDK.Shared.projitems*{5718132f-b918-41c8-9fdc-589df0dfb7a6}*SharedItemsImports = 4 + Virgil.SDK.Tests.Shared\Virgil.SDK.Tests.Shared.projitems*{5718132f-b918-41c8-9fdc-589df0dfb7a6}*SharedItemsImports = 4 Virgil.SDK.Shared\Virgil.SDK.Shared.projitems*{6e4fe86f-7862-4fd9-b2e3-b73ae0957eb6}*SharedItemsImports = 13 - Virgil.SDK.Shared\Virgil.SDK.Shared.projitems*{db5f3e5d-83fd-48bc-8842-95aa70a27928}*SharedItemsImports = 4 - Virgil.SDK.Shared\Virgil.SDK.Shared.projitems*{e597b732-df22-4899-b27b-4c47aac4ee3f}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Android = Debug|Android Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM Debug|iOS = Debug|iOS + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator Debug|Windows Phone (Universal) = Debug|Windows Phone (Universal) Debug|Windows Phone 8 = Debug|Windows Phone 8 Debug|Windows-AnyCPU = Debug|Windows-AnyCPU Debug|Windows-ARM = Debug|Windows-ARM Debug|Windows-x64 = Debug|Windows-x64 Debug|Windows-x86 = Debug|Windows-x86 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Android = Release|Android Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM Release|iOS = Release|iOS + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator Release|Windows Phone (Universal) = Release|Windows Phone (Universal) Release|Windows Phone 8 = Release|Windows Phone 8 Release|Windows-AnyCPU = Release|Windows-AnyCPU Release|Windows-ARM = Release|Windows-ARM Release|Windows-x64 = Release|Windows-x64 Release|Windows-x86 = Release|Windows-x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Android.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Android.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|iOS.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|iOS.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-ARM.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-x64.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Debug|Windows-x86.Build.0 = Debug|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Android.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Android.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Any CPU.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|iOS.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|iOS.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows Phone 8.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-ARM.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-ARM.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-x64.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-x64.Build.0 = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-x86.ActiveCfg = Release|Any CPU - {9BB34DF2-8E60-42FC-A196-73EBE2FD32FD}.Release|Windows-x86.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Android.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|iOS.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|iOS.Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-ARM.Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-x64.Build.0 = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Android.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Android.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|iOS.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|iOS.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows Phone 8.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-ARM.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-ARM.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-x64.ActiveCfg = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-x64.Build.0 = Release|Any CPU - {6B9CE116-871B-4294-AA8E-64DE316AA79A}.Release|Windows-x86.ActiveCfg = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Android.ActiveCfg = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Android.Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|ARM.ActiveCfg = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|iOS.ActiveCfg = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|iOS.Build.0 = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|iPhone.Build.0 = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-ARM.Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-x64.Build.0 = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|x64.ActiveCfg = Debug|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Debug|x86.ActiveCfg = Debug|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Android.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Android.Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|ARM.ActiveCfg = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|iOS.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|iOS.Build.0 = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|iPhone.ActiveCfg = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|iPhone.Build.0 = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows Phone 8.Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-ARM.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-ARM.Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-x64.ActiveCfg = Release|Any CPU - {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-x64.Build.0 = Release|Any CPU {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|Windows-x86.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Android.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Android.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|iOS.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|iOS.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-ARM.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-x64.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Debug|Windows-x86.Build.0 = Debug|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Android.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Android.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Any CPU.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|iOS.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|iOS.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows Phone 8.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-ARM.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-ARM.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-x64.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-x64.Build.0 = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-x86.ActiveCfg = Release|Any CPU - {E597B732-DF22-4899-B27B-4C47AAC4EE3F}.Release|Windows-x86.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Android.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Android.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|iOS.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|iOS.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-ARM.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-x64.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Debug|Windows-x86.Build.0 = Debug|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Android.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Android.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Any CPU.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|iOS.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|iOS.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows Phone 8.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-ARM.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-ARM.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-x64.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-x64.Build.0 = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-x86.ActiveCfg = Release|Any CPU - {6A795FF4-E64B-4770-A50F-329A7D77F618}.Release|Windows-x86.Build.0 = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|x64.ActiveCfg = Release|Any CPU + {DB5F3E5D-83FD-48BC-8842-95AA70A27928}.Release|x86.ActiveCfg = Release|Any CPU + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Android.ActiveCfg = Debug|iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Android.Build.0 = Debug|iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|ARM.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|iOS.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|iOS.Build.0 = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|iPhone.ActiveCfg = Debug|iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|iPhone.Build.0 = Debug|iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows Phone (Universal).ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows Phone 8.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows-AnyCPU.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows-ARM.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows-x64.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|Windows-x86.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|x64.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Debug|x86.ActiveCfg = Debug|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Android.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Any CPU.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|ARM.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|iOS.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|iPhone.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|iPhone.Build.0 = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|iPhoneSimulator.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows Phone (Universal).ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows Phone 8.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows-AnyCPU.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows-ARM.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows-x64.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|Windows-x86.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|x64.ActiveCfg = Release|iPhone + {095DE394-7344-4487-BF42-386B85C730EB}.Release|x86.ActiveCfg = Release|iPhone + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Android.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Android.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|ARM.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iOS.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iOS.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iPhone.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-ARM.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-x64.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|Windows-x86.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|x64.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|x64.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|x86.ActiveCfg = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Debug|x86.Build.0 = Debug|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Android.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Android.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Any CPU.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|ARM.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|ARM.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iOS.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iOS.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iPhone.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iPhone.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows Phone 8.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-ARM.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-ARM.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-x64.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-x64.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-x86.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|Windows-x86.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|x64.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|x64.Build.0 = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|x86.ActiveCfg = Release|Any CPU + {5718132F-B918-41C8-9FDC-589DF0DFB7A6}.Release|x86.Build.0 = Release|Any CPU + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Android.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Any CPU.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|ARM.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|iOS.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|iPhone.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|iPhoneSimulator.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows Phone (Universal).ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows Phone 8.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows-AnyCPU.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows-ARM.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows-x64.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|Windows-x86.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|x64.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|x64.Build.0 = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|x86.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Debug|x86.Build.0 = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Android.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Any CPU.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|ARM.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|iOS.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|iPhone.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|iPhoneSimulator.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows Phone (Universal).ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows Phone 8.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows-AnyCPU.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows-ARM.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows-x64.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|Windows-x86.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|x64.ActiveCfg = Debug|x64 + {2AB003F0-4F95-4FA8-BBF8-181CEA2563C6}.Release|x86.ActiveCfg = Debug|x64 + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Android.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Android.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|ARM.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iOS.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iOS.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iPhone.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-ARM.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-x64.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|Windows-x86.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|x64.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|x64.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|x86.ActiveCfg = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Debug|x86.Build.0 = Debug|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Android.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Android.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Any CPU.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|ARM.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|ARM.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iOS.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iOS.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iPhone.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iPhone.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows Phone 8.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-ARM.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-ARM.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-x64.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-x64.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-x86.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|Windows-x86.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|x64.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|x64.Build.0 = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|x86.ActiveCfg = Release|Any CPU + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C}.Release|x86.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Android.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Android.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|ARM.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iOS.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iOS.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iPhone.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-ARM.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-x64.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|Windows-x86.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|x64.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|x64.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|x86.ActiveCfg = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Debug|x86.Build.0 = Debug|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Android.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Android.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Any CPU.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|ARM.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|ARM.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iOS.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iOS.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iPhone.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iPhone.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows Phone 8.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-ARM.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-ARM.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-x64.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-x64.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-x86.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|Windows-x86.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|x64.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|x64.Build.0 = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|x86.ActiveCfg = Release|Any CPU + {2E6BF5DB-7175-4AA2-A027-D12B22CE98FF}.Release|x86.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Android.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Android.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|ARM.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iOS.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iOS.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iPhone.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows Phone (Universal).Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows Phone 8.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows Phone 8.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-AnyCPU.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-ARM.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-x64.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|Windows-x86.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|x64.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|x64.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Debug|x86.Build.0 = Debug|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Android.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Android.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Any CPU.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|ARM.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|ARM.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iOS.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iOS.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iPhone.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iPhone.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows Phone (Universal).ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows Phone (Universal).Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows Phone 8.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows Phone 8.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-AnyCPU.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-AnyCPU.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-ARM.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-ARM.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-x64.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-x64.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-x86.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|Windows-x86.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|x64.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|x64.Build.0 = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|x86.ActiveCfg = Release|Any CPU + {724BE592-C519-4490-9057-F62F3B2FEE2C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6B9CE116-871B-4294-AA8E-64DE316AA79A} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} {DB5F3E5D-83FD-48BC-8842-95AA70A27928} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} - {E597B732-DF22-4899-B27B-4C47AAC4EE3F} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} + {6B9CE116-871B-4294-AA8E-64DE316AA79A} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} + {801B62A3-AE2E-48E2-B9CD-F9F5C469048C} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} + {724BE592-C519-4490-9057-F62F3B2FEE2C} = {253019A0-C549-4F24-A7A4-E5E0FA4E4591} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EB71B386-CC52-4BA4-925E-4CE02688A29F} + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + Policies = $0 + $0.DotNetNamingPolicy = $1 EndGlobalSection EndGlobal diff --git a/SDK/Source/Virgil.SDK.sln.GhostDoc.user.dic b/SDK/Source/Virgil.SDK.sln.GhostDoc.user.dic deleted file mode 100644 index ddb19b6d..00000000 --- a/SDK/Source/Virgil.SDK.sln.GhostDoc.user.dic +++ /dev/null @@ -1,11 +0,0 @@ -Brainpool -cipherdata -Crypto -Init -Keypair -Koblitz -Locator -Params -plaintext -signer's -virgilsecurity diff --git a/SDK/Source/Virgil.SDK.userprefs b/SDK/Source/Virgil.SDK.userprefs deleted file mode 100644 index 38dbc358..00000000 --- a/SDK/Source/Virgil.SDK.userprefs +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - Virgil.SDK.Droid/Virgil.SDK.Droid.csproj - Virgil.SDK.iOS/Virgil.SDK.iOS.csproj - - \ No newline at end of file