Sending content of a text file to a WCF webservice - javascript

I am working on a project where it involves calling a WCF web service to upload content of a given file to a WCF web service. client is a iPad application written using Titanium Studio. But i am allowed to send files which are less than 8KB in size. but files i am sending can be large in size than 8KB. when i send files which are larger than 8KB, web service return following error message.
The server encountered an error processing the request
Given below is the client code which call
Data is sent to the web service using JSON format.
var readFile = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'log.txt');
modifiedDate = readFile.modificationTimestamp();
var payload ={dateTime: modifiedDate, fileName:'log.txt' , text:readFile};
var xhrLog = Titanium.Network.createHTTPClient();
var serviceUrl = 'http://192.168.134.134/webservice/viewerservice.svc/submitLogData/';
xhrLog.open("POST", serviceUrl);
xhrLog.setRequestHeader("Content-Type", "");
xhrLog.setRequestHeader("Authentication-Token", "605b32dd");
xhrLog.onload = function() {
Ti.API.info(this.responseText);
},
xhrLog.onerror = function() {
}
xhrLog.send(JSON.stringify(sendData));
Following is the service contract and data contract used in the WCF web service to retrive data.
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/SubmitLogData/")]
bool SubmitLogData(List<LogData> log);
Data Contract
[DataContract]
public class LogData
{
[DataMember]
public string dateTime { get; set; }
[DataMember]
public string fileName { get; set; }
[DataMember]
public string text { get; set; }
}

You probably need to increase all the quotas - example of messagesize - would be helpfull if you could enable the WCF server-side tracing and see the exact error message!
UPDATE: example for a wsHttpBinding:
<binding name="wsHttp" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" >
</binding>

Related

RSA PKCS1 V1.5 padding encryption in Node js

I wanna encrypt the symmetric session key (which I'm using for AES encryption) with the RSA algorithm with Padding PKCS1 V1.5 but somehow I'm not getting any library that provides this padding (except node-forge). But in node-forge, I guess the padding is not working correctly, It's breaking on the server side and Saying "Padding is not proper etc".
I tried so many options, I'm referring to the python code(which is working correctly), in that, it provides PKCS1 V1.5 padding properly.
encryptData(sessionKey, publicKey):
sessionKeyBytes = bytes(sessionKey, 'utf-8')
key = RSA.import_key(publicKey)
cipher = PKCS1_v1_5.new(key)
cipherTextBytes = cipher.encrypt(sessionKeyBytes)
cipherText = b64encode(cipherTextBytes).decode()
Any library or something that provides this PKCS1 V1.5 padding properly?
Node Js (node-forge) example code
const forge = require("node-forge");
const fs = require("fs");
const Data = "This is a test";
const publicKeyReading = fs.readFileSync("./publicKeyFinal.pem");
const privateKeyReading = fs.readFileSync("./privateKeyFinal.pem");
const publicKeyFromCert = forge.pki.certificateFromPem(publicKeyReading);
const publicKeyToPem = forge.pki.publicKeyToPem(publicKeyFromCert.publicKey);
const publicKeyFromPem = forge.pki.publicKeyFromPem(publicKeyToPem);
const privateKeyFromPem = forge.pki.privateKeyFromPem(privateKeyReading);
const RSAEncryption = publicKeyFromPem.encrypt(Buffer.from(Data));
const RSADecryption = privateKeyFromPem.decrypt(RSAEncryption);
console.log("RSAEncryption", forge.util.encode64(RSAEncryption));
console.log(RSADecryption);
This decryption is working properly here in Node JS but somehow it's breaking on the server side which is written in C#. I tried standard Node Js crypto too but I guess it doesn't provide PKCS1 V1.5 padding for the encryption (I guess that padding is only for signing and verifying in the Node JS standard lib).
I'm a newbie to asking questions on StackOverflow, so let me know if you need any code or extra info for a better understanding of the problem. I've been working on this project for the past 5 weeks and it's been stuck here for the past 2 weeks.
Thank you in Advance.
Update :
As I got know, That Node JS does provide PKCS1 V1.5 padding and I used that but still it's breaking on the server side and I guess that's because of the oaepHash thing in publicEncrypt method. We're using fOEP as false in c# and I'm not able to fix that value as a false in Node Js(and its default value is 'sha1'), So is there any way that I can set the oaepHash value as false or something?
Note: I can't change the backend code as per Node JS cause it's working on Java, Python and .net too. I've to figure it out according to the backend code.
C# code
public string DecryptData(EncryptionDecryptionParameterDto encryptionDecryptionParams)
{
ValidateDecryptData(encryptionDecryptionParams);
byte[] numArray = Convert.FromBase64String(encryptionDecryptionParams.CipherText);
string str = string.Empty;
var tuple = LoadCertificateAndPrivateKey(encryptionDecryptionParams.PrivateKey, encryptionDecryptionParams.PrivateKeyPassword);
using (RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider())
{
privateKey.ImportParameters(tuple.Item2);
byte[] numArray1 = null;
numArray1 = privateKey.Decrypt(numArray, encryptionDecryptionParams.IsOAEPWithSHA1AndMGF1Padding);
str = Encoding.UTF8.GetString(numArray1);
}
return str;
}
Node Js
const crypto = require("crypto");
const cert = new
X509Certificate(Buffer.from(A66ClientRequest.PublicKey));
const encryptedData = crypto.publicEncrypt(
{
key: cert.publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
Buffer.from(sessionKey),
);
return encryptedData.toString('base64');
LoadCertificateAndPrivateKey() in C#
internal Tuple<Org.BouncyCastle.X509.X509Certificate, RSAParameters> LoadCertificateAndPrivateKey(byte[] privateKey,string pswd)
{
using (MemoryStream ms = new MemoryStream(privateKey))
{
Pkcs12Store pkcs12 = new Pkcs12Store(ms, pswd.ToArray());
string keyAlias = pkcs12.Aliases.Cast<string>().FirstOrDefault(p => pkcs12.IsKeyEntry(p));
return new Tuple<Org.BouncyCastle.X509.X509Certificate, RSAParameters>(pkcs12.GetCertificate(keyAlias).Certificate, DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)pkcs12.GetKey(keyAlias).Key));
}
}
ValidateDecryptData() in C#
protected virtual void ValidateDecryptData(EncryptionDecryptionParameterDto encryptionDecryptionParams, bool checkDataLength = false)
{
if (!encryptionDecryptionParams.CipherText.HasContent())
{
throw new ApplicationException("Cipher Text is missing for RSA decryption.");
}
if (encryptionDecryptionParams.PrivateKey == null)
{
throw new ApplicationException("Private Key is missing for RSA decryption.");
}
if (!encryptionDecryptionParams.PrivateKeyFileName.HasContent())
{
throw new ApplicationException("Private Key File Name is missing for RSA decryption.");
}
if (encryptionDecryptionParams.IsPrivateKeyPasswordPresent && !encryptionDecryptionParams.PrivateKeyPassword.HasContent())
{
throw new ApplicationException("Private Key Password is missing for RSA decryption.");
}
if (checkDataLength && encryptionDecryptionParams.DataLength == 0)
{
throw new ApplicationException("Data length is missing for RSA decryption.");
}
if (encryptionDecryptionParams.SkipMachineKeyFileDeletion ? false : !encryptionDecryptionParams.MachineKeyPath.HasContent())
{
throw new ApplicationException("MachineKeyPath is missing");
}
}
EncryptionDecryptionParameterDto() in C#
public class EncryptionDecryptionParameterDto
{
public string SymmetricCode { get; set; }
public string AsymmetricCode { get; set; }
public CipherMode CipherMode { get; set; }
public string CipherText { get; set; }
public int DataLength { get; set; }
public string InitailVector { get; set; }
public string MachineKeyPath { get; set; }
public string PlainText { get; set; }
public byte[] PrivateKey { get; set; }
public string PrivateKeyFileName { get; set; }
public string PrivateKeyPassword { get; set; }
public byte[] PublicKey { get; set; }
public string PublicKeyFileName { get; set; }
public string SharedKey { get; set; }
public bool SkipMachineKeyFileDeletion { get; set; }
public bool IsOAEPWithSHA1AndMGF1Padding { get; set; }
public bool IsPrivateKeyPasswordPresent { get; set; }
public string Signature { get; set; }
public EncryptionDecryptionParameterDto()
{
CipherMode = CipherMode.ECB;
}
}
Update 2:
I try to decrypt Python encrypted code with Node Js (to figure out which padding and all working for it) and I found out that python encrypted data was not able to decrypt in Node JS with RSA_PKCS1_PADDING but in python code, they mentioned PKCS1 V1.5 padding and I used same in Node JS (as #Topac said Node Js does provide the padding PKCS1 V1.5) and it's throwing me error rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error. I didn't get this where I'm using the same padding but not be able to decrypt in the Node JS with the same padding and key.
I did replace the python example code with the original python code (which I'm referring to)
"
So the answer was very simple but kinda tricky to figure out but #Topaco was very helpful.
It's just that I was loading pfx files(public and private keys in pfx format) in c# and loading Pem files(Pem formatted keys) in Node JS. I used Pem formatted keys instead of pfx in the c# decryption implementation and it worked like a charm.
Thank you #jdweng and #topaco.

How can i hide fcm firebase api key? when i use react-native [duplicate]

I have been trying to read the official docs and guides about how to send message from one device to another. I have saved registration token of both devices in the Real Time Database, thus I have the registration token of another device.
I have tried the following way to send the message
RemoteMessage message = new RemoteMessage.Builder(getRegistrationToken())
.setMessageId(incrementIdAndGet())
.addData("message", "Hello")
.build();
FirebaseMessaging.getInstance().send(message);
However this is not working. The other device doesn't receive any message. I am not even sure, if I can use upstream message sending to conduct device to device communication.
PS: I just want to know if device-to-device messaging is possible using FCM? If yes, then is the code I used have some issue? If yes, then what is the correct way.
Update:
My question was to ask whether device to device messaging without using any separate server other than firebase could messaging is possible or not, if yes than how, since there's no documentation about it. I do not understand what is left to explain here? Anyways I got the answer and will update it as an answer once the question gets reopened.
Firebase has two features to send messages to devices:
the Notifications panel in your Firebase Console allows you to send notifications to specific devices, groups of users, or topics that users subscribed to.
by calling Firebase Cloud Messaging API, you can send messages with whatever targeting strategy you prefer. Calling the FCM API requires access to your Server key, which you should never expose on client devices. That's why you should always run such code on an app server.
The Firebase documentation shows this visually:
Sending messages from one device directly to another device is not supported through the Firebase Cloud Messaging client-side SDKs.
Update: I wrote a blog post detailing how to send notifications between Android devices using Firebase Database, Cloud Messaging and Node.js.
Update 2: You can now also use Cloud Functions for Firebase to send messages securely, without spinning up a server. See this sample use-case to get started. If you don't want to use Cloud Functions, you can run the same logic on any trusted environment you already have, such as your development machine, or a server you control.
Warning There is a very important reason why we don't mention this approach anywhere. This exposes your server key in the APK that
you put on every client device. It can (and thus will) be taken from
there and may lead to abuse of your project. I highly recommend
against taking this approach, except for apps that you only put on
your own devices. – Frank van Puffelen
Ok, so the answer by Frank was correct that Firebase does not natively support device to device messaging. However there's one loophole in that. The Firebase server doesn't identify whether you have send the request from an actual server or are you doing it from your device.
So all you have to do is send a Post Request to Firebase's messaging server along with the Server Key. Just keep this in mind that the server key is not supposed to be on the device, but there's no other option if you want device-to-device messaging using Firebase Messaging.
I am using OkHTTP instead of default way of calling the Rest API. The code is something like this -
public static final String FCM_MESSAGE_URL = "https://fcm.googleapis.com/fcm/send";
OkHttpClient mClient = new OkHttpClient();
public void sendMessage(final JSONArray recipients, final String title, final String body, final String icon, final String message) {
new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... params) {
try {
JSONObject root = new JSONObject();
JSONObject notification = new JSONObject();
notification.put("body", body);
notification.put("title", title);
notification.put("icon", icon);
JSONObject data = new JSONObject();
data.put("message", message);
root.put("notification", notification);
root.put("data", data);
root.put("registration_ids", recipients);
String result = postToFCM(root.toString());
Log.d(TAG, "Result: " + result);
return result;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject resultJson = new JSONObject(result);
int success, failure;
success = resultJson.getInt("success");
failure = resultJson.getInt("failure");
Toast.makeText(getCurrentActivity(), "Message Success: " + success + "Message Failed: " + failure, Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getCurrentActivity(), "Message Failed, Unknown error occurred.", Toast.LENGTH_LONG).show();
}
}
}.execute();
}
String postToFCM(String bodyString) throws IOException {
RequestBody body = RequestBody.create(JSON, bodyString);
Request request = new Request.Builder()
.url(FCM_MESSAGE_URL)
.post(body)
.addHeader("Authorization", "key=" + SERVER_KEY)
.build();
Response response = mClient.newCall(request).execute();
return response.body().string();
}
I hope Firebase will come with a better solution in future. But till then, I think this is the only way. The other way would be to send topic message or group messaging. But that was not in the scope of the question.
Update:
The JSONArray is defined like this -
JSONArray regArray = new JSONArray(regIds);
regIds is a String array of registration ids, you want to send this message to. Keep in mind that the registration ids must always be in an array, even if you want it to send to a single recipient.
I have also been using direct device to device gcm messaging in my prototype. It has been working very well. We dont have any server. We exchange GCM reg id using sms/text and then communicate using GCM after that. I am putting here code related to GCM handling
**************Sending GCM Message*************
//Sends gcm message Asynchronously
public class GCM_Sender extends IntentService{
final String API_KEY = "****************************************";
//Empty constructor
public GCM_Sender() {
super("GCM_Sender");
}
//Processes gcm send messages
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Action Service", "GCM_Sender Service Started");
//Get message from intent
String msg = intent.getStringExtra("msg");
msg = "\"" + msg + "\"";
try{
String ControllerRegistrationId = null;
//Check registration id in db
if(RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().size() > 0 ) {
String controllerRegIdArray[] = RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().get(1);
if(controllerRegIdArray.length>0)
ControllerRegistrationId = controllerRegIdArray[controllerRegIdArray.length-1];
if(!ControllerRegistrationId.equalsIgnoreCase("NULL")){
// 1. URL
URL url = new URL("https://android.googleapis.com/gcm/send");
// 2. Open connection
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
// 3. Specify POST method
urlConnection.setRequestMethod("POST");
// 4. Set the headers
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", "key=" + API_KEY);
urlConnection.setDoOutput(true);
// 5. Add JSON data into POST request body
JSONObject obj = new JSONObject("{\"time_to_live\": 0,\"delay_while_idle\": true,\"data\":{\"message\":" + msg + "},\"registration_ids\":[" + ControllerRegistrationId + "]}");
// 6. Get connection output stream
OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
out.write(obj.toString());
out.close();
// 6. Get the response
int responseCode = urlConnection.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null){
response.append(inputLine);
}
in.close();
Log.d("GCM getResponseCode:", new Integer(responseCode).toString());
}else{
Log.d("GCM_Sender:","Field REGISTRATION_TABLE is null");
}
}else {
Log.d("GCM_Sender:","There is no Registration ID in DB ,please sync devices");
}
} catch (Exception e) {
e.printStackTrace();
//MessageSender.getInstance().sendMessage(msg, Commands.SMS_MESSAGE);
}
}
//Called when service is no longer alive
#Override
public void onDestroy() {
super.onDestroy();
//Do a log that GCM_Sender service has been destroyed
Log.d("Action Service", "GCM_Sender Service Destroyed");
}
}
**************Receiving GCM Message*************
public class GCM_Receiver extends WakefulBroadcastReceiver {
public static final String RETRY_ACTION ="com.google.android.c2dm.intent.RETRY";
public static final String REGISTRATION ="com.google.android.c2dm.intent.REGISTRATION";
public SharedPreferences preferences;
//Processes Gcm message .
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
GCMNotificationIntentService.class.getName());
//Start GCMNotificationIntentService to handle gcm message asynchronously
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
/*//Check if DatabaseService is running .
if(!DatabaseService.isServiceRunning) {
Intent dbService = new Intent(context,DatabaseService.class);
context.startService(dbService);
}*/
//Check if action is RETRY_ACTION ,if it is then do gcm registration again .
if(intent.getAction().equals(RETRY_ACTION)) {
String registrationId = intent.getStringExtra("registration_id");
if(TextUtils.isEmpty(registrationId)){
DeviceRegistrar.getInstance().register(context);
}else {
//Save registration id to prefs .
preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("BLACKBOX_REG_ID",registrationId);
editor.commit();
}
} else if (intent.getAction().equals(REGISTRATION)) {
}
}
}
//Processes gcm messages asynchronously .
public class GCMNotificationIntentService extends IntentService{
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
String gcmData;
private final String TAG = "GCMNotificationIntentService";
//Constructor with super().
public GCMNotificationIntentService() {
super("GcmIntentService");
}
//Called when startService() is called by its Client .
//Processes gcm messages .
#Override
protected void onHandleIntent(Intent intent) {
Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Started");
Bundle extras = intent.getExtras();
//Get instance of GoogleCloudMessaging .
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
//Get gcm message type .
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) {
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
.equals(messageType)) {
sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
sendNotification("Deleted messages on server: "
+ extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
.equals(messageType)) {
Log.i(TAG, "Completed work # " + SystemClock.elapsedRealtime());
gcmData = extras.getString("message");
Intent actionService = new Intent(getApplicationContext(),Action.class);
actionService.putExtra("data", gcmData);
//start Action service .
startService(actionService);
//Show push notification .
sendNotification("Action: " + gcmData);
//Process received gcmData.
Log.d(TAG,"Received Gcm Message from Controller : " + extras.getString("message"));
}
}
GCM_Receiver.completeWakefulIntent(intent);
}
//Shows notification on device notification bar .
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(this, BlackboxStarter.class);
//Clicking on GCM notification add new layer of app.
notificationIntent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this).setSmallIcon(R.drawable.gcm_cloud)
.setContentTitle("Notification from Controller")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
//Play default notification
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
}
//Called when service is no longer be available .
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Destroyed");
}
}
According to the new documentation which was updated on October 2, 2018 you must send post request as below
https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA //Server key
{
"to": "sent device's registration token",
"data": {
"hello": "message from someone",
}
}
To get device's registration token extend FirebaseMessagingService and override onNewToken(String token)
For more info refer to doc https://firebase.google.com/docs/cloud-messaging/android/device-group
I am late but above solutions has helped me to write down this simple answer, you can send your message directly to android devices from android application, here is the simple implementation I have done and it works great for me.
compile android volley library
compile 'com.android.volley:volley:1.0.0'
Just copy paste this simple function ;) and your life will become smooth just like knife in butter. :D
public static void sendPushToSingleInstance(final Context activity, final HashMap dataValue /*your data from the activity*/, final String instanceIdToken /*firebase instance token you will find in documentation that how to get this*/ ) {
final String url = "https://fcm.googleapis.com/fcm/send";
StringRequest myReq = new StringRequest(Request.Method.POST,url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(activity, "Bingo Success", Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(activity, "Oops error", Toast.LENGTH_SHORT).show();
}
}) {
#Override
public byte[] getBody() throws com.android.volley.AuthFailureError {
Map<String, Object> rawParameters = new Hashtable();
rawParameters.put("data", new JSONObject(dataValue));
rawParameters.put("to", instanceIdToken);
return new JSONObject(rawParameters).toString().getBytes();
};
public String getBodyContentType()
{
return "application/json; charset=utf-8";
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Authorization", "key="+YOUR_LEGACY_SERVER_KEY_FROM_FIREBASE_CONSOLE);
headers.put("Content-Type","application/json");
return headers;
}
};
Volley.newRequestQueue(activity).add(myReq);
}
Note
If you want to send message to topics so you can change parameter instanceIdToken to something like /topics/topicName.
For groups implementation is the same but you just need to take care of parameters. checkout Firebase documentation and you can pass those parameters.
let me know if you face any issue.

converting a piece of javascript code to c# access API

I need a C# code that will trigger a nprinting task. On our server we are not allowed to evoke html file, hence I can't use javascript attached.
The attached works just need to translate it to .net as I can't use html on our server
Javascripts below works just fine
<html>
<head>
</head>
<body>
<h1>NPrinting API task starter</h1>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
(function(){
console.log("started")
var taskIDs=[
"f3ebd873-b310-4a22-a269-24ce81b8ce74"
]
$.ajax({
url: 'URL:4993/api/v1/login/ntlm',
xhrFields: {
withCredentials: true
}
}).done(function(data) {
console.log(data);
for(var i=0;i<taskIDs.length;i++){
$.ajax({
type: "POST",
url: 'URL:4993/api/v1/tasks/'+taskIDs[i]+'/executions',
xhrFields: {
withCredentials: true
}
}).done(function(data) {
console.log("task "+i);
console.log(data);
if(i==taskIDs.length)
open(location, '_self').close();
});
}
});
})();
<!-- open(location, '_self').close(); -->
</script>
</body>
</html>
C# code which I can't complete all the below works but doesn't start the task.
//Create the HTTP Request (authenticate) and add required headers
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL:4993/api/v1/login/ntlm");
CookieContainer cookies = new CookieContainer();
request.CookieContainer = cookies;
request.Method = "GET";
request.UserAgent = "Windows";
request.Accept = "application/json";
// specify to run as the current Microsoft Windows user
request.UseDefaultCredentials = true;
try
{
// make the web request and return the content
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string sResponseHTML = responseReader.ReadToEnd();
Console.WriteLine(sResponseHTML);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Create second HTTP request (get list of apps) and add required headers
HttpWebRequest secondRequest = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/tasks/f3ebd873-b310-4a22-a269-24ce81b8ce74/executions");
//assign cookie to request to maintain session
secondRequest.CookieContainer = cookies;
secondRequest.Method = "POST";
secondRequest.UserAgent = "Windows";
secondRequest.Accept = "application/json";
// specify to run as the current Microsoft Windows user
secondRequest.UseDefaultCredentials = true;
Thanks
I found a solution to the above, request.
Nprinting API task to run from C#
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Post_Request_API
{
class Program
{
static void Main(string[] args)
{
//Create the HTTP Request (authenticate) and add required headers
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/login/ntlm");
//Assign custom SSL certificate validation method if certificate is untrusted
//request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
CookieContainer cookies = new CookieContainer();
request.CookieContainer = cookies;
request.Method = "GET";
request.UserAgent = "Windows";
request.Accept = "application/json";
//Specify to run as the current Microsoft Windows user
request.UseDefaultCredentials = true;
try
{
// make the web request and return the content
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string sResponseHTML = responseReader.ReadToEnd();
Console.WriteLine(sResponseHTML);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Create second HTTP request to add a new user and required headers
HttpWebRequest secondRequest = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/tasks/f3ebd873-b310-4a22-a269-24ce81b8ce74/executions");
//Assign custom SSL certificate validation method if certificate is untrusted
//secondRequest.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
//Add the XSRF token
secondRequest.Headers.Add("X-XSRF-TOKEN", cookies.GetCookies(request.RequestUri)["NPWEBCONSOLE_XSRF-TOKEN"].Value);
secondRequest.CookieContainer = cookies;
secondRequest.Method = "POST";
secondRequest.UserAgent = "Windows";
secondRequest.Accept = "application/json";
secondRequest.ContentType = "application/json";
//Specify to run as the current Microsoft Windows user
secondRequest.UseDefaultCredentials = true;
//Prepare JSON object to send to the remote server
JsonUser user = new JsonUser();
user.ID = "";
user.type = "";
user.task = "";
user.created = "";
user.lastUpdate = "";
user.completed = "";
user.progress = "";
user.status = "Enqueued";
user.result = "";
user.priority = "";
string jUserString = JsonConvert.SerializeObject(user);
using (var streamWriter = new StreamWriter(secondRequest.GetRequestStream()))
{
streamWriter.Write(jUserString);
streamWriter.Flush();
streamWriter.Close();
}
try
{
HttpWebResponse response2 = (HttpWebResponse)secondRequest.GetResponse();
StreamReader responseReader2 = new StreamReader(response2.GetResponseStream());
string sResponseHTML2 = responseReader2.ReadToEnd();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public class JsonUser
{
public string ID { get; set; }
public string type { get; set; }
public string task { get; set; }
public string created { get; set; }
public string lastUpdate { get; set; }
public string completed { get; set; }
public string progress { get; set; }
public string status { get; set; }
public string result { get; set; }
public string priority { get; set; }
}
}
}

Html to pdf conversion and download

I have an Angular web app for simple quizzes, at the end of the last quiz I bind the result into an HTML template.
Previously I could generate a pdf file using PHP mpdf library from this HTML template, now as I am building the business logic and the security in spring boot I want to do that as well in spring boot.
I used Flying saucer and i could generate a pdf file from an HTML-template in the resources folder.
The question is how can I get this HTML file from the front end and generate a pdf file out of it and download the last to my pc?
#Service
public class PdfService {
private static final String OUTPUT_FILE = "test.pdf";
private static final String UTF_8 = "UTF-8";
#Test
public void generatePdf() throws Exception {
// We set-up a Thymeleaf rendering engine. All Thymeleaf templates
// are HTML-based files located under "src/test/resources". Beside
// of the main HTML file, we also have partials like a footer.html or
// a header. We can re-use those partials in different documents.
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(HTML);
templateResolver.setCharacterEncoding(UTF_8);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
// The data in our Thymeleaf templates is not hard-coded. Instead,
// we use placeholders in our templates. We fill these placeholders
// with actual data by passing in an object. In this example, we will
// write a letter to "John Doe".
//
// Note that we could also read this data from a JSON file, a database
// a web service or whatever.
Data data = exampleDataForJohnDoe();
Context context = new Context();
context.setVariable("data", data);
// Flying Saucer needs XHTML - not just normal HTML. To make our life
// easy, we use JTidy to convert the rendered Thymeleaf template to
// XHTML. Note that this might not work for very complicated HTML. But
// it's good enough for a simple letter.
String renderedHtmlContent = templateEngine.process("template", context);
String xHtml = convertToXhtml(renderedHtmlContent);
ITextRenderer renderer = new ITextRenderer();
renderer.getFontResolver().addFont("Code39.ttf", IDENTITY_H, EMBEDDED);
// FlyingSaucer has a working directory. If you run this test, the working directory
// will be the root folder of your project. However, all files (HTML, CSS, etc.) are
// located under "/src/test/resources". So we want to use this folder as the working
// directory.
String baseUrl = FileSystems
.getDefault()
.getPath("src", "test", "resources")
.toUri()
.toURL()
.toString();
renderer.setDocumentFromString(xHtml, baseUrl);
renderer.layout();
// And finally, we create the PDF:
OutputStream outputStream = new FileOutputStream(OUTPUT_FILE);
renderer.createPDF(outputStream);
outputStream.close();
}
private Data exampleDataForJohnDoe() {
Data data = new Data();
data.setFirstname("John");
data.setLastname("Doe");
data.setStreet("Example Street 1");
data.setZipCode("12345");
data.setCity("Example City");
return data;
}
static class Data {
private String firstname;
private String lastname;
private String street;
private String zipCode;
private String city;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
private String convertToXhtml(String html) throws UnsupportedEncodingException {
Tidy tidy = new Tidy();
tidy.setInputEncoding(UTF_8);
tidy.setOutputEncoding(UTF_8);
tidy.setXHTML(true);
ByteArrayInputStream inputStream = new ByteArrayInputStream(html.getBytes(UTF_8));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
tidy.parseDOM(inputStream, outputStream);
return outputStream.toString(UTF_8);
}

File upload with ember-upload, how to fill request with additional data for servicestack?

For introduction, I have problem with communication between servicestack and application written in ember.js via REST, I am using ember-uploader component to upload a file to service stack.
View hbs:
<table class="table table-bordered table-hover">
{{file-upload}}
</table>
component in coffee script
ABC.FileUploadComponent = Ember.FileField.extend(
url: "/api/upload"
filesDidChange: (->
uploadUrl = #get("url")
console.log uploadUrl
files = #get("files")
test = { fileName: "test" }
uploader = Ember.Uploader.create(
url: uploadUrl
)
uploader.upload(files[0],test) unless Ember.isEmpty(files)
console.log files
return
).observes("files")
)
component in javascript
ABC.FileUploadComponent = Ember.FileField.extend({
url: "/api/upload",
filesDidChange: (function() {
var files, test, uploadUrl, uploader;
uploadUrl = this.get("url");
console.log(uploadUrl);
files = this.get("files");
test = {
fileName: "test"
};
uploader = Ember.Uploader.create({
url: uploadUrl,
data: test
});
if (!Ember.isEmpty(files)) {
uploader.upload(files[0], test);
}
console.log(files);
}).observes("files")
});
My service model:
namespace ABC.Service.ServiceModel
{
public class Upload
{
[Route("/upload")]
public class UploadRequest : IRequiresRequestStream
{
public System.IO.Stream RequestStream { set; get; }
public object FileName { set; get; }
}
public class UploadResponse
{
public int Successed { set; get; }
}
}
}
My Service Method
namespace ABC.Service.Service
{
public class UploadService : ServiceBase // Service base inherites from ServiceStack.Service
{
public Upload.UploadResponse Post(Upload.UploadRequest request)
{
var req = base.Request;
var reqThatIwant = request.FileName;
return new Upload.UploadResponse() { Successed = 1 };
}
}
}
and here is screen from watch :
So my question is, how I have to change the code to get data marked as "2" into Request object marked as "1" (marked on the screen)?
Handling Raw Request Stream
When you use IRequiresRequestStream you're saying you want to take over deserializing the Request and access the raw input HTTP Request Body as a Stream. As a result ServiceStack wont attempt to read from the Request body and instead inject the HTTP Request stream - in this case the only Request DTO parameters it will be able to populate are those on the /pathinfo or ?QueryString, e.g:
[Route("/upload/{FileName}")]
public class Upload : IRequiresRequestStream
{
public Stream RequestStream { set; get; }
public string FileName { set; get; }
}
Accessing FormData HTTP POSTs
But if the JavaScript component is sending you HTTP POST FormData (i.e. application/x-www-form-urlencoded or multipart/form-data) than it's very unlikely you want to treat it like a raw Request Stream but instead access the Request.FormData or Request.Files that were posted.
Handling File Upload examples
Based on your screenshot, the HTTP Request Content-Type is multipart/form-data which case you will most likely be able to access any uploaded files using Request.Files.
Some examples of accessing HTTP Uploaded Files are available in the Live Demos:
Imgur - Save uploaded files to a MemoryStream
public object Post(Upload request)
{
foreach (var uploadedFile in Request.Files
.Where(uploadedFile => uploadedFile.ContentLength > 0))
{
using (var ms = new MemoryStream())
{
uploadedFile.WriteTo(ms);
WriteImage(ms);
}
}
return HttpResult.Redirect("/");
}
Rest Files - Save to FileSystem
public void Post(Files request)
{
var targetDir = GetPath(request);
var isExistingFile = targetDir.Exists
&& (targetDir.Attributes & FileAttributes.Directory) != FileAttributes.Directory;
if (isExistingFile)
throw new NotSupportedException(
"POST only supports uploading new files. Use PUT to replace contents of an existing file");
if (!Directory.Exists(targetDir.FullName))
Directory.CreateDirectory(targetDir.FullName);
foreach (var uploadedFile in base.Request.Files)
{
var newFilePath = Path.Combine(targetDir.FullName, uploadedFile.FileName);
uploadedFile.SaveTo(newFilePath);
}
}
HTTP Benchmarks - Handle multiple and .zip uploaded files
public object Post(UploadTestResults request)
{
//...
foreach (var httpFile in base.Request.Files)
{
if (httpFile.FileName.ToLower().EndsWith(".zip"))
{
using (var zip = ZipFile.Read(httpFile.InputStream))
{
var zipResults = new List<TestResult>();
foreach (var zipEntry in zip)
{
using (var ms = new MemoryStream())
{
zipEntry.Extract(ms);
var bytes = ms.ToArray();
var result = new MemoryStream(bytes).ToTestResult();
zipResults.Add(result);
}
}
newResults.AddRange(zipResults);
}
}
else
{
var result = httpFile.InputStream.ToTestResult();
newResults.Add(result);
}
}
}

Categories

Resources