Phone Number Authentication for Firebase Through Unity (C#) - c#

I'm trying to get phone number authentication for Unity up and running but I am getting no SMS response. The documentation online is super unclear about how to do this. I'd much rather have Google Auth for Firebase but apparently it isn't supported yet. Can anyone help me figure out how to get this up and running?
Here is what I have so far...
public class SignIn : MonoBehaviour {
private string phoneNumber;
private string secureCode;
private uint phoneAuthTimeoutMs;
private Firebase.Auth.FirebaseAuth firebaseAuth;
private Credential credential;
private string verificationId;
private string verificationCode;
public Text PhoneNumberInputFieldText;
public Text SecureCodeInputFieldText;
public Button SendSecureCodeButton;
public Button SubmitSecureCodeButton;
// Use this for initialization
void Start()
{
SendSecureCodeButton.GetComponent<Button>().onClick.AddListener(() => StartSignIn());
}
// Update is called once per frame
void Update () {
}
void StartSignIn()
{
firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
phoneAuthTimeoutMs = 60000;
phoneNumber = PhoneNumberInputFieldText.text;
Debug.Log(phoneNumber);
if (PlayerPrefs.GetString("secureCode") != null)
{
verificationId = PlayerPrefs.GetString("secureCode");
}
PhoneAuthProvider provider = PhoneAuthProvider.GetInstance(firebaseAuth);
provider.VerifyPhoneNumber(phoneNumber, phoneAuthTimeoutMs, null,
verificationCompleted: (credential) =>
{
// Auto-sms-retrieval or instant validation has succeeded (Android only).
// There is no need to input the verification code.
// `credential` can be used instead of calling GetCredential().
},
verificationFailed: (error) =>
{
// The verification code was not sent.
// `error` contains a human readable explanation of the problem.
},
codeSent: (id, token) =>
{
//Prompt here to type in SecureCode
PlayerPrefs.SetString("secureCode", id);
credential = provider.GetCredential(verificationId, verificationCode);
firebaseAuth.SignInWithCredentialAsync(credential).ContinueWith(task => {
if (task.IsFaulted)
{
Debug.LogError("SignInWithCredentialAsync encountered an error: " +
task.Exception);
return;
}
FirebaseUser newUser = task.Result;
Debug.Log("User signed in successfully");
// This should display the phone number.
Debug.Log("Phone number: " + newUser.PhoneNumber);
// The phone number providerID is 'phone'.
Debug.Log("Phone provider ID: " + newUser.ProviderId);
});
// Verification code was successfully sent via SMS.
// `id` contains the verification id that will need to passed in with
// the code from the user when calling GetCredential().
// `token` can be used if the user requests the code be sent again, to
// tie the two requests together.
},
codeAutoRetrievalTimeOut: (id) =>
{
// Called when the auto-sms-retrieval has timed out, based on the given
// timeout parameter.
// `id` contains the verification id of the request that timed out.
});
}
}
Thanks in advance!
Here is my Firebase Console:

I'll post an answer but i'll edit this.
Try a simplier sending SMS phone verification
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
phoneNumber = "your phone number here";//state the phone number here first
uint phoneAuthTimeoutMs = 10000;
PhoneAuthProvider provider = PhoneAuthProvider.GetInstance(auth);
provider.VerifyPhoneNumber(phoneNumber, phoneAuthTimeoutMs,null,
verificationCompleted: (credential) => {
},
verificationFailed: (error) => {
},
codeSent: (id, token) => {
MyText.text = "SMS Has been sent " + id;
},
codeAutoRetrievalTimeOut : (id) => {
});
MyText.text += "HMM";
Then please tell me if it works. Now if it works we will proceed to the next step

Related

Notification on change of data in Xamarin/C#

Hi so I've implemented a method based on this answer:
How to get notification in xamarin forms on firebase data change?
But I'm having trouble getting it working.
Here's my code:
void DoFirebaseObserve()
{
var firebase = new FirebaseClient(Constants.FirebaseProjectUrl);
firebase.Child("RegisterUserTable").AsObservable<RegisterUser>().Subscribe(obs =>
{
switch (obs.EventType)
{
case Firebase.Database.Streaming.FirebaseEventType.InsertOrUpdate:
Console.WriteLine("InsertOrUpdate");
break;
case Firebase.Database.Streaming.FirebaseEventType.Delete:
Console.WriteLine("Delete");
break;
default:
break;
}
});
}
I call this code in the OnAppearing method of my app's home page. I've tried with and without the while (true) {} condition.
When I add, update or delete a record in firebase, nothing happens in my application. The writelines are never called.
Any help would be appreciated. Thanks.
So I worked out how to do it through using Google Cloud Functions in the Firebase console.
Step 1. Set up FCM in your .Net code
Follow this tutorial:
https://learn.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/remote-notifications-with-fcm?tabs=macos
Once you have got your FCM token from that device, you can add it to your realtime database (I did this myself in the firebase console manually for testing).
Step 2. Set up Cloud Functions
Follow this tutorial:
https://www.youtube.com/watch?v=bpI3Bbhlcas&t=1104s&ab_channel=uNicoDev
Step 3. Create a function to send the message
You can use this node.js code in your cloud functions to send up to 500 devices:
// Create a list containing up to 500 registration tokens.
// These registration tokens come from the client FCM SDKs.
const registrationTokens = [
'YOUR_REGISTRATION_TOKEN_1',
// …
'YOUR_REGISTRATION_TOKEN_N',
];
const message = {
data: {score: '850', time: '2:45'},
tokens: registrationTokens,
};
admin.messaging().sendMulticast(message)
.then((response) => {
console.log(response.successCount + ' messages were sent successfully');
});
Source: https://firebase.google.com/docs/cloud-messaging/send-message#node.js_1
Code Example
Some of my code to help you get an idea of how to go about doing something like this. Can't guarantee this is the optimal method but it works.
const reference = "JourneyTbl/{journeyId}";
// newJourneyAdded | listener method | Send push notif when new journey created:
exports.newJourneyAdded = functions.database.ref(reference)
.onCreate((event, context) => {
// where fcm tokens are stored:
const refNotifications = "NotificationTbl";
// get ref to RegNotTable:
const refFcm = admin.database().ref(refNotifications);
// array to hold all fcms from table:
const allFcms = [];
// get value of "NotificationTbl":
refFcm.on("value", (snapshot) => {
// check if there's any children:
if (snapshot.hasChildren()) {
// loop through children:
snapshot.forEach((element) => {
// stringify the data:
const asString = JSON.stringify(element);
// parse that as a JSON object:
const asJson = JSON.parse(asString);
// add fcm token to array:
allFcms.push(asJson.fcm);
});
}
// if array contains something:
if (allFcms.length > 0) {
// construct message to send:
const msg = {
notification: {
title: "Notification Title goes here",
body: "Notification Body goes here ",
},
tokens: allFcms, // pass the tokens
};
// send that message:
admin.messaging().sendMulticast(msg)
.then((response) => {
console.log(response.successCount + " mgs were sent sfly");
});
} else {
console.log("No devices in FCM tokens list");
}
});
return "ok";
});

Getting error with Stripe: No such payment_intent: 'my payment intent id'

sorry I'm pretty new to coding so I don't know many of the abbreviations/shorthand stuff.
So I'm working with React and C# trying to use Stripe to handle payments and I've gotten to the point where I am getting back a payment_intent id, client_secret, and payment method Id, but when I run the code:
const result = await stripe.confirmCardPayment(this.state.clientSecret, {
payment_method: paymentMethodRQ.paymentMethod.id,
});
I get the error:
No such payment_intent. Which is a 404 for the /v1/payment_intent/confirm
I guess that means the payment intent isn't actually being created since it doesn't show up on the Stripe dashboard either. Not really sure how to fix this. Most of the other similar questions either use different languages or don't address how to solve my particular issue. I followed the documentation for collecting payments then paying out, found at https://stripe.com/docs/connect/collect-then-transfer-guide#setup
This is my React code for the submit:
handleSubmit = async (event) => {
event.preventDefault();
const { stripe, elements } = this.props;
if (!stripe || !elements) {
_logger("Stripe.js has not yet loaded.");
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
const paymentMethodRQ = await stripe.createPaymentMethod({
type: "card",
card: elements.getElement(CardElement),
});
const result = await stripe.confirmCardPayment(this.state.clientSecret, {
payment_method: paymentMethodRQ.paymentMethod.id,
});
if (result.error) {
toast.error("payment not processed");
_logger(result.error.message, "payment not processed");
} else {
toast.success("The payment processing!");
if (result.paymentIntent.status === "succeeded") {
_logger("payument successful");
// havent gotten to this part yet
}
}
};
I am passing in an amount and currency for the PaymentIntentCreateOptions from React.
and this is my controller for the payment intent in Visual Studio:
[HttpPost("paymentintent")]
public async Task<IActionResult> PaymentIntent(PaymentIntentCreateOptions options)
{
StripeConfiguration.ApiKey = "my test secret key";
ItemResponse<PaymentIntentModel> response = new ItemResponse<PaymentIntentModel>();
var service = new PaymentIntentService();
var paymentIntent = service.Create(options);
Logger.LogInformation(paymentIntent.ToString());
var paymentIntentModel = new PaymentIntentModel();
paymentIntentModel.Id = paymentIntent.Id;
paymentIntentModel.ClientSecretKey = paymentIntent.ClientSecret;
response.Item = paymentIntentModel;
return Ok200(response);
}
You have to make sure that your public key you declare in the frontend matches your public key in your stripe account otherwise you will get this error.

Conversation always restarts in Directline BOT channel websocket, how to keep it flowing?

I have built an app that needs to connect to a Bot DirectLine - websockets channel to interact in conversations via LUIS and sms with Twilio.
To make the bot talk to the app I wrote a mvc controller that relays messages.
I am not sure this approach is correct, I made it up from some samples.
It works, but the main problem is that my code seems to always start a new conversation when a message is received from the client, so the context is not maintained.
How can I keep the conversation flowing and not restarting at every message?
I mean, the steps should be, for example:
Bot: Hello, what's your name?
User: Carl
Bot: Pleased to meet you Carl!
instead I get:
Bot: Hello, what's your name?
User: Carl
Bot: Sorry, I can't help you with that.
like the conversation is restarted from scratch.
Here is my controller code (the Twilio webhook is set to https://mySmsMVCapp.azurewebsites.net/smsapp/):
public class smsappController : TwilioController
{
private static string directLineSecret = ConfigurationManager.AppSettings["DirectLineSecret"];
private static string botId = ConfigurationManager.AppSettings["BotId"];
const string accountSid = "obfuscated";
const string authToken = "obfuscated";
private static string fromUser = "DirectLineSampleClientUser";
private string SMSreply = "";
public async Task<TwiMLResult> Index(SmsRequest incomingMessage)
{
// Obtain a token using the Direct Line secret
var tokenResponse = await new DirectLineClient(directLineSecret).Tokens.GenerateTokenForNewConversationAsync();
// Use token to create conversation
var directLineClient = new DirectLineClient(tokenResponse.Token);
var conversation = await directLineClient.Conversations.StartConversationAsync();
using (var webSocketClient = new WebSocket(conversation.StreamUrl))
{
webSocketClient.OnMessage += WebSocketClient_OnMessage;
// You have to specify TLS version to 1.2 or connection will be failed in handshake.
webSocketClient.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
webSocketClient.Connect();
while (true)
{
string input = incomingMessage.Body;
if (!string.IsNullOrEmpty(input))
{
if (input.ToLower() == "exit")
{
break;
}
else
{
if (input.Length > 0)
{
Activity userMessage = new Activity
{
From = new ChannelAccount(fromUser),
Text = input,
Type = ActivityTypes.Message
};
await directLineClient.Conversations.PostActivityAsync(conversation.ConversationId, userMessage);
//break;
if (!string.IsNullOrEmpty(SMSreply))
{
var messagingResponse = new MessagingResponse();
var message = messagingResponse.AddChild("Message");
message.AddText(SMSreply); //send text
SMSreply = string.Empty;
return TwiML(messagingResponse);
}
}
}
}
}
}
return null;
}
private void WebSocketClient_OnMessage(object sender, MessageEventArgs e)
{
// Occasionally, the Direct Line service sends an empty message as a liveness ping. Ignore these messages.
if (!string.IsNullOrWhiteSpace(e.Data))
{
var activitySet = JsonConvert.DeserializeObject<ActivitySet>(e.Data);
var activities = from x in activitySet.Activities
where x.From.Id == botId
select x;
foreach (Activity activity in activities)
{
if (!string.IsNullOrEmpty(activity.Text))
{
SMSreply = activity.Text;
}
}
}
}
}
The issue was actually I wasn't saving and retrieving conversationID.
For the moment I am testing using a static variable to store the value.
Then I reconnect to the conversation with it and the conversation with the bot keeps in context.

SFSafariViewController notification when token received

Converting the code in the following swift sample to C# (Xamarin) to notify the App when Paypal Token is received inside SFSafariViewController but it does not fire the method.
https://github.com/paypal/paypal-here-sdk-ios-distribution/blob/master/SampleApp/PPHSDKSampleApp/InitializeViewController.swift
Converted the swift to C# as following but after user login to PayPal and receives the token, Safari is not closing to fire SetupMerchant()
UrlSchemes is also set to retailsdksampleapp to match the sample swift app from PayPal.
SafariDelegate safariDelegate = new SafariDelegate(this);
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("kCloseSafariViewControllerNotification"), safariDelegate.SetupMerchant);
void loadBrowser()
{
var url = new NSUrl("https://paypalauth.herokuapp.com/toPayPal/" + Application.paypalEnvironment + "?returnTokenOnQueryString=true");
var svc = new SFSafariViewController(url);
svc.Delegate = safariDelegate;
this.PresentViewController(svc, true, null);
}
public class SafariDelegate : SFSafariViewControllerDelegate
{
ViewController _controller = null;
public SafariDelegate(ViewController controller)
{
_controller = controller;
}
public void SetupMerchant(NSNotification notification)
{
// Dismiss the SFSafariViewController when the notification of token has been received.
this._controller.PresentedViewController?.DismissViewController(true, () => { });
// Grab the token(s) from the notification and pass it into the merchant initialize call to set up
// the merchant. Upon successful initialization, the 'Connect Card Reader' button will be
// enabled for use.
var accessToken = notification.Object.ToString();
}
}
When running the swift sample app from Paypal, it closes the browser (SFSafariViewController) after login and fires the SetupMerchant() but not in the C# code. There is possibly a missing step or invalid code conversion.
If the Safari controller is not closing and you have the proper UrlScheme set (), then you are missing the OpenUrl override in your AppDelegate class that listening for your app's url schemes and posts the notification that your view controller is listening for.
Example:
[Export("application:openURL:sourceApplication:annotation:")]
public bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
if (sourceApplication == "com.apple.SafariViewService")
{
var dict = HttpUtility.ParseQueryString(url.Query);
var token = dict["access_token"];
NSNotificationCenter.DefaultCenter.PostNotificationName("kCloseSafariViewControllerNotification", new NSString(token));
};
return true;
}

Can't insert data with Firebase

After I heard about Firebase, I decided it was a good idea to try it on my little Unity game.
I readed the documentation, followed the "Get Started" configuration tutorials, and changed the authentication rules so everyone could insert data.
void Start()
{
// Set up the Editor before calling into the realtime database.
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("https://magicast-bd2fc.firebaseio.com/");
Firebase.Auth.FirebaseAuth.DefaultInstance.StateChanged += DefaultInstance_StateChanged;
// Get the root reference location of the database.
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
var u = new User();
u.email = "sdjkdsdksadjsad";
u.fb_id = "sakdsajdhasd";
u.username = "jadhsjahjsda";
reference.SetValueAsync(u);
}
This code does execute, but when I go to my Firebase Console, I see no data on the Database tab. I can't figure out what I am doing wrong, and the code gives no errors at all! What am I doing wrong?
This is my user class. It's basically a testing class, no big stuff:
public class User
{
public string username;
public string email;
public string fb_id;
public User()
{
}
public User(string username, string email, string fb_id)
{
this.username = username;
this.email = email;
this.fb_id = fb_id;
}
}
You can't call .set() on arbitrary objects to the Firebase Database, they must come under one of the following categories:
string
long
double
bool
Dictionary<string, Object>
List<Object>
Instead of
reference.SetValueAsync(u);
You need to call
string json = JsonUtility.ToJson(u);
reference.SetRawJsonValueAsync(json);
You are also not actually logging in any user. To log in an anonymous user, first go to the Firebase Console -> Authentication and turn on the 'Anonymous' switch. Then authenticate with the following code:
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
auth.SignInAnonymouslyAsync().ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInAnonymouslyAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInAnonymouslyAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
newUser.DisplayName, newUser.UserId);
});
You are not authenticated and the default Firebase security rules require that auth != null.
See the docs for how to authenticate with Unity.

Categories

Resources