Repository: rlamasb/Firebase.Xamarin
Branch: master
Commit: 1fbd4149a048
Files: 47
Total size: 118.9 KB
Directory structure:
gitextract_p1_b5ys5/
├── .gitignore
├── Auth/
│ ├── FirebaseAuth.cs
│ ├── FirebaseAuthException.cs
│ ├── FirebaseAuthLink.cs
│ ├── FirebaseAuthProvider.cs
│ ├── FirebaseAuthType.cs
│ ├── FirebaseConfig.cs
│ ├── IFirebaseAuthProvider.cs
│ └── User.cs
├── Database/
│ ├── FirebaseClient.cs
│ ├── FirebaseKeyGenerator.cs
│ ├── FirebaseObject.cs
│ ├── GlobalSuppressions.cs
│ ├── Http/
│ │ ├── HttpClientExtensions.cs
│ │ └── PostResult.cs
│ ├── ObservableExtensions.cs
│ ├── Offline/
│ │ ├── ExceptionEventArgs.cs
│ │ ├── OfflineCacheAdapter.cs
│ │ ├── OfflineEntry.cs
│ │ ├── RealtimeDatabase.cs
│ │ └── SyncOptions.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── Query/
│ │ ├── AuthQuery.cs
│ │ ├── ChildQuery.cs
│ │ ├── FilterQuery.cs
│ │ ├── FirebaseQuery.cs
│ │ ├── IFirebaseQuery.cs
│ │ ├── OrderQuery.cs
│ │ ├── ParameterQuery.cs
│ │ ├── QueryExtensions.cs
│ │ └── QueryFactoryExtensions.cs
│ └── Streaming/
│ ├── FirebaseCache.cs
│ ├── FirebaseEvent.cs
│ ├── FirebaseEventType.cs
│ ├── FirebaseServerEventType.cs
│ └── FirebaseSubscription.cs
├── Firebase.Xamarin.csproj
├── Firebase.Xamarin.sln
├── LICENSE
├── Notification/
│ └── PushNotification.cs
├── Properties/
│ └── AssemblyInfo.cs
├── README.md
├── Token/
│ ├── StreamToken.cs
│ ├── TokenGenerator.cs
│ └── TokenOptions.cs
├── TokenGenerator.config
└── packages.config
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
#Autosave files
*~
#build
[Oo]bj/
[Bb]in/
packages/
TestResults/
# globs
Makefile.in
*.DS_Store
*.sln.cache
*.suo
*.cache
*.pidb
*.userprefs
*.usertasks
config.log
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.user
*.tar.gz
tarballs/
test-results/
Thumbs.db
#Mac bundle stuff
*.dmg
*.app
#resharper
*_Resharper.*
*.Resharper
#dotCover
*.dotCover
================================================
FILE: Auth/FirebaseAuth.cs
================================================
namespace Firebase.Xamarin.Auth
{
using Newtonsoft.Json;
///
/// The firebase auth.
///
public class FirebaseAuth
{
///
/// Gets or sets the firebase token which can be used for authenticated queries.
///
[JsonProperty("idToken")]
public string FirebaseToken
{
get;
set;
}
///
/// Gets or sets the refresh token of the underlying service which can be used to get a new access token.
///
[JsonProperty("refreshToken")]
public string RefreshToken
{
get;
set;
}
///
/// Gets or sets the numbers of seconds until the token expires.
///
[JsonProperty("expiresIn")]
public int ExpiresIn
{
get;
set;
}
///
/// Gets or sets the user.
///
public User User
{
get;
set;
}
}
}
================================================
FILE: Auth/FirebaseAuthException.cs
================================================
using System;
using System.Runtime.Serialization;
namespace Firebase.Xamarin.Auth
{
/*
* Sign In Exceptions
*/
public class FirebaseIncorrectPasswordException : Exception
{
///
/// Default constructor
///
public FirebaseIncorrectPasswordException() : base()
{
}
///
/// Argument constructor
///
/// This is the description of the exception
public FirebaseIncorrectPasswordException(String message) : base(message)
{
}
///
/// Argument constructor with inner exception
///
/// This is the description of the exception
/// Inner exception
public FirebaseIncorrectPasswordException(String message, Exception innerException) : base(message, innerException)
{
}
}
public class FirebaseInvalidEmailException : Exception
{
///
/// Default constructor
///
public FirebaseInvalidEmailException() : base()
{
}
///
/// Argument constructor
///
/// This is the description of the exception
public FirebaseInvalidEmailException(String message) : base(message)
{
}
///
/// Argument constructor with inner exception
///
/// This is the description of the exception
/// Inner exception
public FirebaseInvalidEmailException(String message, Exception innerException) : base(message, innerException)
{
}
}
/*
* Create User Exceptions
*/
public class FirebaseUsedEmailException : Exception
{
///
/// Default constructor
///
public FirebaseUsedEmailException() : base()
{
}
///
/// Argument constructor
///
/// This is the description of the exception
public FirebaseUsedEmailException(String message) : base(message)
{
}
///
/// Argument constructor with inner exception
///
/// This is the description of the exception
/// Inner exception
public FirebaseUsedEmailException(String message, Exception innerException) : base(message, innerException)
{
}
}
public class FirebaseWeakPasswordException : Exception
{
///
/// Default constructor
///
public FirebaseWeakPasswordException() : base()
{
}
///
/// Argument constructor
///
/// This is the description of the exception
public FirebaseWeakPasswordException(String message) : base(message)
{
}
///
/// Argument constructor with inner exception
///
/// This is the description of the exception
/// Inner exception
public FirebaseWeakPasswordException(String message, Exception innerException) : base(message, innerException)
{
}
}
}
================================================
FILE: Auth/FirebaseAuthLink.cs
================================================
namespace Firebase.Xamarin.Auth
{
using System.Threading.Tasks;
///
/// The firebase auth which can be linked to another credentials.
///
public class FirebaseAuthLink : FirebaseAuth
{
internal FirebaseAuthLink()
{
}
internal FirebaseAuthProvider AuthProvider
{
get;
set;
}
///
/// Links the user with an email and password.
///
/// The email.
/// The password.
/// The .
public Task LinkToAsync(string email, string password)
{
return this.AuthProvider.LinkAccountsAsync(this, email, password);
}
///
/// Links the this user with and account from a third party provider.
///
/// The auth type.
/// The access token retrieved from login provider of your choice.
/// The .
public Task LinkToAsync(FirebaseAuthType authType, string oauthAccessToken)
{
return this.AuthProvider.LinkAccountsAsync(this, authType, oauthAccessToken);
}
}
}
================================================
FILE: Auth/FirebaseAuthProvider.cs
================================================
namespace Firebase.Xamarin.Auth
{
using System;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
///
/// The auth token provider.
///
public class FirebaseAuthProvider : IDisposable, IFirebaseAuthProvider
{
private const string GoogleIdentityUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key={0}";
private const string GoogleSignUpUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key={0}";
private const string GooglePasswordUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={0}";
private const string GooglePasswordResetUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}";
private const string GoogleSetAccountUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}";
private readonly FirebaseConfig authConfig;
private readonly HttpClient client;
///
/// Initializes a new instance of the class.
///
/// The auth config.
public FirebaseAuthProvider(FirebaseConfig authConfig)
{
this.authConfig = authConfig;
this.client = new HttpClient();
}
///
/// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.
///
/// The auth type.
/// The access token retrieved from login provider of your choice.
/// The .
public async Task SignInWithOAuthAsync(FirebaseAuthType authType, string oauthAccessToken)
{
var providerId = this.GetProviderId(authType);
var content = $"{{\"postBody\":\"access_token={oauthAccessToken}&providerId={providerId}\",\"requestUri\":\"http://localhost\",\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GoogleIdentityUrl, content).ConfigureAwait(false);
}
///
/// Sign in user anonymously. He would still have a user id and access token generated, but name and other personal user properties will be null.
///
/// The .
public async Task SignInAnonymouslyAsync()
{
var content = $"{{\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GoogleSignUpUrl, content).ConfigureAwait(false);
}
///
/// Using the provided email and password, get the firebase auth with token and basic user credentials.
///
/// The email.
/// The password.
/// The .
public async Task SignInWithEmailAndPasswordAsync(string email, string password)
{
var content = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GooglePasswordUrl, content).ConfigureAwait(false);
}
///
/// Creates new user with given credentials.
///
/// The email.
/// The password.
/// The .
public async Task CreateUserWithEmailAndPasswordAsync(string email, string password)
{
var content = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GoogleSignUpUrl, content).ConfigureAwait(false);
}
///
/// Sends user an email with a link to reset his password.
///
/// The email.
public async Task SendPasswordResetEmailAsync(string email)
{
var content = $"{{\"requestType\":\"PASSWORD_RESET\",\"email\":\"{email}\"}}";
var response = await this.client.PostAsync(new Uri(string.Format(GooglePasswordResetUrl, this.authConfig.ApiKey)), new StringContent(content, Encoding.UTF8, "application/json")).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
}
///
/// Links the authenticated user represented by with an email and password.
///
/// The authenticated user to link with specified email and password.
/// The email.
/// The password.
/// The .
public async Task LinkAccountsAsync(FirebaseAuth auth, string email, string password)
{
var content = $"{{\"idToken\":\"{auth.FirebaseToken}\",\"email\":\"{email}\",\"password\":\"{password}\",\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GoogleSetAccountUrl, content).ConfigureAwait(false);
}
///
/// Links the authenticated user represented by with and account from a third party provider.
///
/// The auth.
/// The auth type.
/// The access token retrieved from login provider of your choice.
/// The .
public async Task LinkAccountsAsync(FirebaseAuth auth, FirebaseAuthType authType, string oauthAccessToken)
{
var providerId = this.GetProviderId(authType);
var content = $"{{\"idToken\":\"{auth.FirebaseToken}\",\"postBody\":\"access_token={oauthAccessToken}&providerId={providerId}\",\"requestUri\":\"http://localhost\",\"returnSecureToken\":true}}";
return await this.SignInWithPostContentAsync(GoogleIdentityUrl, content).ConfigureAwait(false);
}
///
/// Disposes all allocated resources.
///
public void Dispose()
{
this.client.Dispose();
}
private async Task SignInWithPostContentAsync(string googleUrl, string postContent)
{
var response = await this.client.PostAsync(new Uri(string.Format(googleUrl, this.authConfig.ApiKey)), new StringContent(postContent, Encoding.UTF8, "application/json")).ConfigureAwait(false);
var responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var jsonReturn = JObject.Parse(responseData);
var message = (string)jsonReturn["error"]["message"];
// Login
// Email address not found in database
if (message.Equals("EMAIL_NOT_FOUND"))
{
throw new FirebaseInvalidEmailException("Email address not found");
}
// Login
// Invalid password supplied
else if (message.Equals("INVALID_PASSWORD"))
{
throw new FirebaseIncorrectPasswordException("Incorrect passord");
}
// New User
// Email address already exists
else if (message.Equals("EMAIL_EXISTS"))
{
throw new FirebaseUsedEmailException("Email address already exists");
}
// New User
// Week Password
else if (message.Contains("WEAK_PASSWORD"))
{
throw new FirebaseWeakPasswordException("Weak password, must be at least 6 characters");
}
// Just end on default status check
else
{
response.EnsureSuccessStatusCode();
}
}
var user = JsonConvert.DeserializeObject(responseData);
var auth = JsonConvert.DeserializeObject(responseData);
auth.User = user;
auth.AuthProvider = this;
return auth;
}
private string GetProviderId(FirebaseAuthType authType)
{
switch (authType)
{
case FirebaseAuthType.Facebook:
return "facebook.com";
case FirebaseAuthType.Google:
return "google.com";
case FirebaseAuthType.Github:
return "github.com";
case FirebaseAuthType.Twitter:
return "twitter.com";
default: throw new NotImplementedException("");
}
}
}
}
================================================
FILE: Auth/FirebaseAuthType.cs
================================================
namespace Firebase.Xamarin.Auth
{
///
/// The type of authentication.
///
public enum FirebaseAuthType
{
///
/// The facebook auth.
///
Facebook,
///
/// The google auth.
///
Google,
///
/// The github auth.
///
Github,
///
/// The twitter auth.
///
Twitter
}
}
================================================
FILE: Auth/FirebaseConfig.cs
================================================
namespace Firebase.Xamarin.Auth
{
///
/// The auth config.
///
public class FirebaseConfig
{
///
/// Initializes a new instance of the class.
///
/// The api key of your Firebase app.
public FirebaseConfig(string apiKey)
{
this.ApiKey = apiKey;
}
///
/// Initializes a new instance of the class.
///
/// API key.
/// API key for push notification.
public FirebaseConfig(string apiKey, string apiKeyForPushNotification)
{
this.ApiKey = apiKey;
this.ApiKeyForPushNotification = apiKeyForPushNotification;
}
///
/// Gets or sets the api key of your Firebase app.
///
public string ApiKey
{
get;
set;
}
///
/// Gets or sets the API key for push notification.
///
/// The API key for push notification.
public string ApiKeyForPushNotification
{
get;
set;
}
}
}
================================================
FILE: Auth/IFirebaseAuthProvider.cs
================================================
namespace Firebase.Xamarin.Auth
{
using System.Threading.Tasks;
///
/// The auth token provider.
///
public interface IFirebaseAuthProvider
{
///
/// Creates new user with given credentials.
///
/// The email.
/// The password.
/// The .
Task CreateUserWithEmailAndPasswordAsync(string email, string password);
///
/// Sends user an email with a link to reset his password.
///
/// The email.
/// The .
Task SendPasswordResetEmailAsync(string email);
///
/// Sign in user anonymously. He would still have a user id and access token generated, but name and other personal user properties will be null.
///
/// The .
Task SignInAnonymouslyAsync();
///
/// Using the provided email and password, get the firebase auth with token and basic user credentials.
///
/// The email.
/// The password.
/// The .
Task SignInWithEmailAndPasswordAsync(string email, string password);
///
/// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.
///
/// The auth type.
/// The access token retrieved from login provider of your choice.
/// The .
Task SignInWithOAuthAsync(FirebaseAuthType authType, string oauthAccessToken);
///
/// Links the authenticated user represented by with an email and password.
///
/// The authenticated user to link with specified email and password.
/// The email.
/// The password.
/// The .
Task LinkAccountsAsync(FirebaseAuth auth, string email, string password);
///
/// Links the authenticated user represented by with and account from a third party provider.
///
/// The auth.
/// The auth type.
/// The access token retrieved from login provider of your choice.
/// The .
Task LinkAccountsAsync(FirebaseAuth auth, FirebaseAuthType authType, string oauthAccessToken);
}
}
================================================
FILE: Auth/User.cs
================================================
namespace Firebase.Xamarin.Auth
{
using System.ComponentModel;
using Newtonsoft.Json;
///
/// Basic information about the logged in user.
///
public class User
{
///
/// Gets or sets the local id.
///
[JsonProperty("localId", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string LocalId
{
get;
set;
}
///
/// Gets or sets the federated id.
///
[JsonProperty("federatedId", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string FederatedId
{
get;
set;
}
///
/// Gets or sets the first name.
///
[JsonProperty("firstName", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string FirstName
{
get;
set;
}
///
/// Gets or sets the last name.
///
[JsonProperty("lastName", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string LastName
{
get;
set;
}
///
/// Gets or sets the display name.
///
[JsonProperty("displayName", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string DisplayName
{
get;
set;
}
///
/// Gets or sets the email.
///
[JsonProperty("email", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string Email
{
get;
set;
}
///
/// Gets or sets the photo url.
///
[JsonProperty("photoUrl", DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string PhotoUrl
{
get;
set;
}
}
}
================================================
FILE: Database/FirebaseClient.cs
================================================
namespace Firebase.Xamarin.Database
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Firebase.Xamarin.Database.Offline;
using Firebase.Xamarin.Database.Query;
///
/// Firebase client which acts as an entry point to the online database.
///
public class FirebaseClient
{
internal readonly Func> OfflineDatabaseFactory;
internal readonly Func> AuthTokenAsyncFactory;
private readonly string baseUrl;
///
/// Initializes a new instance of the class.
///
/// The base url.
public FirebaseClient(string baseUrl) : this(baseUrl, (t, s) => new Dictionary())
{
}
///
/// Initializes a new instance of the class.
///
/// The base url.
/// Offline database.
public FirebaseClient(string baseUrl, Func> offlineDatabaseFactory)
{
this.OfflineDatabaseFactory = offlineDatabaseFactory;
this.baseUrl = baseUrl;
if (!this.baseUrl.EndsWith("/"))
{
this.baseUrl += "/";
}
}
///
/// Initializes a new instance of the class.
///
/// The base url.
/// Factory which returns valid firebase auth token.
public FirebaseClient(string baseUrl, Func> authTokenAsyncFactory)
: this(baseUrl, authTokenAsyncFactory, (t, s) => new Dictionary())
{
}
///
/// Initializes a new instance of the class.
///
/// The base url.
/// Factory which returns valid firebase auth token.
/// Offline database.
public FirebaseClient(string baseUrl, Func> authTokenAsyncFactory, Func> offlineDatabaseFactory)
: this(baseUrl, offlineDatabaseFactory)
{
this.AuthTokenAsyncFactory = authTokenAsyncFactory;
}
///
/// Queries for a child of the data root.
///
/// Name of the child.
/// .
public ChildQuery Child(string resourceName)
{
return new ChildQuery(this, () => this.baseUrl + resourceName);
}
}
}
================================================
FILE: Database/FirebaseKeyGenerator.cs
================================================
namespace Firebase.Xamarin.Database
{
using System;
using System.Text;
///
/// Offline key generator which mimics the official Firebase generators.
/// Credit: https://github.com/bubbafat/FirebaseSharp/blob/master/src/FirebaseSharp.Portable/FireBasePushIdGenerator.cs
///
public class FirebaseKeyGenerator
{
// Modeled after base64 web-safe chars, but ordered by ASCII.
private const string PushCharsString = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
private static readonly char[] PushChars;
private static readonly DateTimeOffset Epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
private static readonly Random random = new Random();
private static readonly byte[] lastRandChars = new byte[12];
// Timestamp of last push, used to prevent local collisions if you push twice in one ms.
private static long lastPushTime;
static FirebaseKeyGenerator()
{
PushChars = Encoding.UTF8.GetChars(Encoding.UTF8.GetBytes(PushCharsString));
}
///
/// Returns next firebase key based on current time.
///
///
/// The .
public static string Next()
{
// We generate 72-bits of randomness which get turned into 12 characters and
// appended to the timestamp to prevent collisions with other clients. We store the last
// characters we generated because in the event of a collision, we'll use those same
// characters except "incremented" by one.
var id = new StringBuilder(20);
var now = (long)(DateTimeOffset.Now - Epoch).TotalMilliseconds;
var duplicateTime = now == lastPushTime;
lastPushTime = now;
var timeStampChars = new char[8];
for (int i = 7; i >= 0; i--)
{
var index = (int)(now % PushChars.Length);
timeStampChars[i] = PushChars[index];
now = (long)Math.Floor((double)now / PushChars.Length);
}
if (now != 0)
{
throw new Exception("We should have converted the entire timestamp.");
}
id.Append(timeStampChars);
if (!duplicateTime)
{
for (int i = 0; i < 12; i++)
{
lastRandChars[i] = (byte)random.Next(0, PushChars.Length);
}
}
else
{
// If the timestamp hasn't changed since last push, use the same random number,
// except incremented by 1.
var lastIndex = 11;
for (; lastIndex >= 0 && lastRandChars[lastIndex] == PushChars.Length - 1; lastIndex--)
{
lastRandChars[lastIndex] = 0;
}
lastRandChars[lastIndex]++;
}
for (int i = 0; i < 12; i++)
{
id.Append(PushChars[lastRandChars[i]]);
}
if (id.Length != 20)
{
throw new Exception("Length should be 20.");
}
return id.ToString();
}
}
}
================================================
FILE: Database/FirebaseObject.cs
================================================
namespace Firebase.Xamarin.Database
{
///
/// Holds the object of type along with its key.
///
/// Type of the underlying object.
public class FirebaseObject
{
internal FirebaseObject(string key, T obj)
{
this.Key = key;
this.Object = obj;
}
///
/// Gets the key of .
///
public string Key
{
get;
}
///
/// Gets the underlying object.
///
public T Object
{
get;
}
}
}
================================================
FILE: Database/GlobalSuppressions.cs
================================================
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
================================================
FILE: Database/Http/HttpClientExtensions.cs
================================================
namespace Firebase.Xamarin.Database.Http
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
///
/// The http client extensions for object deserializations.
///
internal static class HttpClientExtensions
{
///
/// The get object collection async.
///
/// The client.
/// The request uri.
/// The type of entities the collection should contain.
/// The .
public static async Task>> GetObjectCollectionAsync(this HttpClient client, string requestUri)
{
var data = await client.GetStringAsync(requestUri).ConfigureAwait(false);
var dictionary = JsonConvert.DeserializeObject>(data);
if (dictionary == null)
{
return new FirebaseObject[0];
}
return dictionary.Select(item => new FirebaseObject(item.Key, item.Value)).ToList();
}
///
/// The get object collection async.
///
/// The json data.
/// The type of entities the collection should contain.
/// The .
public static IEnumerable> GetObjectCollection(this string data, Type elementType)
{
var dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType);
var dictionary = JsonConvert.DeserializeObject(data, dictionaryType) as IDictionary;
if (dictionary == null)
{
yield break;
}
foreach (DictionaryEntry item in dictionary)
{
yield return new FirebaseObject