Blazor Server App Multipart Form from iPhone Content Length is 0 - iphone

I have this code in my WEB API that validates if the content received is multipart:
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
I do this from my Blazor Web App to POST the content:
private async Task LoadImage(InputFileChangeEventArgs e)
{
MultipartFormDataContent content;
var file = e.File;
var fileContent = new StreamContent(file.OpenReadStream());
fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
content = new MultipartFormDataContent();
content.Add(
content: fileContent,
name: "\"file\"",
fileName: file.Name);
var metadataContent = new StringContent(JsonConvert.SerializeObject(metadata));
content.Add(
content: metadataContent,
name: "\"metadata\""
);
using (HttpClient httpClient = new HttpClient())
{
var response = await httpClient.PostAsync(Configuration["backendurl"] + "/api/saveimage/save", content);
}
If I post the form from my PC browser everything works. BUT if I post the same information from an iPhone the Content-Length is 0 and the IsMimeMultipartContent() returns false in my backend.

Related

Facebook complains that the app is not secure

When I try to login via Facebook, it throws the following error;
facebook has detected app isn't using a secure connection to transfer information
But I'm pretty sure that it is secured via 'Let's encrypt'.
I have checked Web and Client OAuth login boxes and set the corresponding redirect uris on developer facebook.
On maui side, I am calling the following code piece and AppSettings.BaseUrl is correct, I have checked that;
WebAuthenticatorResult authResult = await WebAuthenticator.Default.AuthenticateAsync(
new WebAuthenticatorOptions()
{
Url = new Uri($"{AppSettings.BaseUrl}account/authentication/{scheme}"),
CallbackUrl = new Uri("tibi://"),
PrefersEphemeralWebBrowserSession = true
});
And on backend side, the following api is requested;
[HttpGet("authentication/{scheme}")]
[AllowAnonymous]
public async Task Get([FromRoute] string scheme)
{
var auth = await Request.HttpContext.AuthenticateAsync(scheme);
if (!auth.Succeeded
|| auth?.Principal == null
|| !auth.Principal.Identities.Any(id => id.IsAuthenticated)
|| string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token")))
{
// Not authenticated, challenge
await Request.HttpContext.ChallengeAsync(scheme);
}
else
{
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
var email = string.Empty;
email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value;
// Get parameters to send back to the callback
var qs = new Dictionary<string, string>
{
{ "access_token", auth.Properties.GetTokenValue("access_token") },
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
{ "expires_in", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() },
{ "email", email }
};
// Build the result url
var url = callbackScheme + "://#" + string.Join(
"&",
qs.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
// Redirect to final url
Request.Host = HostString.FromUriComponent(AppSettingsProvider.GatewayUrl);
Request.HttpContext.Response.Redirect(url);
}
}
Challenge is invoked successfully and redirects me to the Facebook login but when I sign in, I get the error above.

Outlook JS Add-in: Credentials from Token (On-Premise Exchange, Not OAuth)

Because of a limitation in message size in the Office API, I am trying to build a service that:
Office client gets identity token (getCallbackTokenAsync)
Posts message including identity token to service
Service creates new new Exchange Service, with new Token Credential
Limitations:
The EWS server is on premise, and it is currently not possible to use OAuth
I'm currently using this as a RESTful service
I have tried getUserIdentityToken, but that is not useful for credentials.
Office JS call
var _appName;
var _mailbox;
var _emailAddress;
var _itemId;
var _identityToken;
var _ewsUrl;
app.initialize();
_mailbox = Office.context.mailbox;
var item = _mailbox.item;
_itemId = item.itemId;
_ewsUrl = _mailbox.ewsUrl;
_emailAddress = _mailbox.userProfile.emailAddress;
function MakeRequest(serviceUrl, callType, format) {
_mailbox.getCallbackTokenAsync(function (asyncResult) {
if (asyncResult.error) {
app.showNotification(_appName, "Error getting Use Identity Token: " + asyncResult.error.message);
}
else {
_identityToken = asyncResult.value;
var correctedItemId = _itemId.replace("+", "_");
var request = { ItemId: correctedItemId, UserEmailAddress: _emailAddress, UserIdentityToken: _identityToken, EwsUrl: _ewsUrl, AudienceUrl: _audUrl, ReturndNewId: false };
$.ajax({
crossDomain: true,
url: serviceUrl,
type: callType,
data: JSON.stringify(request),
contentType: 'application/json; charset=utf-8',
dataType: format,
success: function (asyncResultSuccess) {
LogResult(asyncResultSuccess.statusText);
//app.showNotification(_appName, asyncResultSuccess.statusText);
},
error: function (asyncResultError) {
LogResult(asyncResultError.statusText);
//app.showNotification(_appName, asyncResultError.statusText);
}
});
}
});
}
Server Side Credential:
void LoadSimple()
{
try
{
service = new ExchangeService(ExchangeVersion.Exchange2013_SP1)
{
Credentials = new TokenCredentials(RequestProperties.UserIdentityToekn),
Url = new Uri(RequestProperties.EwsUrl)
};
ReturnProps = new EwsReturnItem();
}
catch (Exception ex)
{
log.Error(string.Format("{0}: {1}", MethodBase.GetCurrentMethod().Name, ex.Message));
}
}
Server Side Forward Message:
public EwsReturnItem Forward(string toRecipient, string ccRecipient, string subjectPrepend, string bodyText)
{
try
{
var correctedId = CorrectItemId(RequestProperties.ItemId);
EmailMessage email = EmailMessage.Bind(service, correctedId, new PropertySet(ItemSchema.MimeContent, ItemSchema.Subject));
ResponseMessage forwardMessage = email.CreateForward();
forwardMessage.Subject = String.Format("{0}{1}", subjectPrepend, email.Subject);
forwardMessage.ToRecipients.Add(toRecipient);
forwardMessage.CcRecipients.Add(ccRecipient);
forwardMessage.BodyPrefix = bodyText;
...snip
}
catch (Exception ex)
{
log.Error(string.Format("{0}: {1}", MethodBase.GetCurrentMethod().Name, ex.Message));
return new EwsReturnItem() { StatusText = ex.Message };
}
}
It fails as unauthorized on this line:
EmailMessage email = EmailMessage.Bind(service, correctedId, new PropertySet(ItemSchema.MimeContent, ItemSchema.Subject));

Using angular 4 to send form-data

Hi I'm building a WordPress theme and I need to use contact form 7 plugin on it, but I can't figure out the correct way to send the form data to the plugin.
here is my post service:
import {
Injectable
} from '#angular/core';
import {
HttpClient,
HttpHeaders
} from '#angular/common/http';
#Injectable()
export class FormsService {
constructor(private http: HttpClient) {}
postForm(url, form) {
return this.http.post(url, form, {
headers: new HttpHeaders().set('Content-Type', 'multipart/form-data'),
})
}
}
and the component part that use the service:
onSubmit() {
const fd = new FormData();
fd.append('your-name', this.name);
fd.append('your-email', this.email);
fd.append('your-message', this.message);
fd.append('your-subject', this.sumbject);
const url = `/wp-json/contact-form-7/v1/contact-forms/${this.form_id}/feedback`;
this.sendMsg.postForm(url, fd).subscribe(
data => {
console.log(data);
},
err => console.log({
error: err
})
)
this.submitted = true;
}
At this point the server response that the message was submitted ok, but when I go to the WP admin page, non of the field get the values.
But If I use postman with this url and params the form all works as I want.
I also found another solution that works but its not the angular way as I want to be.
the solution
onSubmit() {
const url = `/wp-json/contact-form-7/v1/contact-forms/${this.form_id}/feedback`;
this.submitted = true;
}
sendData(url) {
let XHR = new XMLHttpRequest();
const FD = new FormData();
FD.append('your-name', this.name);
FD.append('your-email', this.email);
FD.append('your-message', this.message);
FD.append('your-subject', this.subject);
// Define what happens on successful data submission
XHR.addEventListener('load', function(event) {
alert('Yeah! Data sent and response loaded.');
});
// Define what happens in case of error
XHR.addEventListener('error', function(event) {
alert('Oups! Something went wrong.');
});
// Set up our request
XHR.open('POST', url);
// Send our FormData object; HTTP headers are set automatically
XHR.send(FD);
}
I found my solution, the problem was on the headers definitions of my service, the correct way is:
postForm(url, body) {
var headers = new HttpHeaders();
headers.append('Content-Type', 'application/form-data');
return this.http.post(url, body, {headers: headers })
}

Google Vision Rest API in Xamarin

I'm trying to call the Google Vision REST API from a Xamarin.Forms app. I have the following code:-
private async void SendToGoogle(MediaFile file)
{
using (HttpClient client = new HttpClient())
{
string uri = "https://vision.googleapis.com/v1/images:annotate?key=API_KEY";
HttpResponseMessage response;
var stream = file.GetStream();
using (var content = new StreamContent(stream))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentLength = stream.Length;
response = await client.PostAsync(uri, content);
var resp = await response.Content.ReadAsStringAsync();
}
}
}
But this is returning me a 400 error message:
Invalid JSON payload received. Expected a value.

Ember send rest after other rests ended

I have action where i send information with attachments. If information have files they are sended thru function uploadInformationImage (rest) to server and this function returs their id in database.
main function is sending rest data to store information to database.
But information is saved before files uploaded. How can i save information AFTER uploading files?
actions: {
addInformation: function() {
var that = this;
var title = $('#title1').val();
var information = '';
var blocksInOrder = $("#body_container").sortable("toArray");
blocksInOrder.forEach(function(item) {
Ember.RSVP.all([
that.uploadInformationImage(item).then(function(response) {
return response['document']['id'];
})
]).then(function(docId) {
information += '<p class="' + blocktype + '">Download file</p>';
});
});
var dataObject = {
'title': title,
'information': information
};
Ember.$.ajax({
url: ENV.apiHost + "/api/informations/add_new",
type: 'POST',
contentType: "application/json",
data: JSON.stringify(dataObject)
});
}
}