My app has a form for users to enter a string of content and a pass-key, which is posted to the server and encrypted. The users are given the encrypted value back. The app allows them to send the encrypted value back to the server with the pass-key and the server will decrypt the data and send it back in the response.
I can successfully post the data for encrypting and get my response back. The issue I have though is that the encrypted data contains characters that need to be URL encoded when the users post the encrypted data back.
This is the Angular 4 service function that requests the encryption.
encrypt(data: CryptoData): Promise<Result> {
let urlParameters = new URLSearchParams();
urlParameters.append('content', data.content);
urlParameters.append('key', data.key);
let body = urlParameters.toString();
return this.http
.post('/api/encrypt', body, this.options)
.toPromise()
.then(response =>
{
return response.json();
});
}
This gets back the encrypted result. Using a Content and Key value of:
content: Foo Bar
key: Test Key
result: AAAAABAAAACUdwXxU1tfClnbpOaKEqNVPuZSxL+cawqTxH+ZAFmDlBAAAAD6o/EFwKE9aDIU1WLOCDtBbY7ERTiKgsXr4pnsvkm+Et+qpJwLORrvPn9QzmJ1uFI=
The result up there is a Base64 string and it contains characters, such as +, that I need to URL encode when the user posts the data back.
What is the angular way to handle this? The backend server is ASP.Net Core and I'm open to changing how my implementation there is done to handle any changes on the Angular side. At the moment I'm posting the data with this function, which causes the + characters to be replaced with spaces.
export class EncryptService implements OnInit {
private options: RequestOptions;
constructor(private http: Http) {
this.options = new RequestOptions({
headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' })
})
}
decrypt(data: CryptoData) {
let urlParameters = new URLSearchParams();
urlParameters.append('content', data.content);
urlParameters.append('key', data.key);
let body = urlParameters.toString();
return this.http
.post('/api/decrypt', body, this.options)
.toPromise()
.then(response =>
{
return response.json();
});
}
}
The interface being passed in looks like this:
export interface CryptoData {
content: string;
key: string;
}
My ASP.Net Core API end-point looks like this:
[HttpPost("~/api/Decrypt")]
public IActionResult Decrypt([FromForm] CryptoRequest request)
{
string content = request.Content;
string key = request.Key;
// .....
return base.Ok();
}
Use base64URL instead on base64.
For Angular, use base64URL.
Run npm install base64url
In your service or component beneath your imports, add the following:
const base64url = require('base64url');
Use like this..
const b64URLresult = base64url(result);
There is an alternative way to add javascript packages using Typings and Definitely Typed.. Didn't work first try for me on this package so gave the above solution.
And in your controller. Use Microsoft.AspNetCore.WebUtilities.Base64UrlDecode
Related
I have a web application I am developing that depends on back end processing. I am sending a post request from my Angular(v14)/Typescript front end to an ASP.NET back end.
Back end code
[HttpPost]
public async Task<string> ProcessExcelFile(IFormFile fileData, IFormCollection data)
{
string guid = await processor.ProcessFile(fileData, data) //Imp not important for question.
return guid;
}
Front end code
var guid: string = "";
this.http.post<string>('/api', formData).subscribe(result => {guid = result;});
I have confirmed the backend is being hit correctly through debugging and returns the correct data.
But the front end "guid" is empty after I call the post request. What I am doing wrong here?
The back end processing could take a few seconds, is that the problem? What can I do about this?
In case it's a JSON response you should be able to do it like this:
// Backend response
{
"guid": "randomId123",
}
let guid: string;
this.http.post<any>('/api', formData).subscribe(result => {
guid = result.guid;
});
If it's not JSON Response, could please share how the response look alike?
Update in case the response is just text:
let guid: string;
this.http.post<string>('/api', formData,{ responseType:'text'}).subscribe(result => {
guid = result;
});
Just by going through the code snippets, not returning an IActionResult stands out to me so you could give this is a shot and check if it solves the issue
[HttpPost]
public async Task<IActionResult> ProcessExcelFile(IFormFile fileData, IFormCollection data)
{
string guid = await
processor.ProcessFile(fileData, data) //Imp not important for question.
return ok(guid);
}
This basically sends an OK API response with the guid as the content
It looks like the post request would not finalize until the function it lived in that started from a button click on the web page finished.
Instead of creating the guid variable in the same function as the post request, I changed it to a global variable. I am now getting the correct data in the guid variable but only after the button press function finishes.
this.http.post<string>('/api', formData).subscribe(result => {this.guid = result;});
I have build a http post web api in asp which return the following string in Json
RootObject rootObject = new RootObject()
{
status = "User Registered"
};
msg = JsonConvert.SerializeObject(rootObject);
Below is my angular js controller in which I am consuming that web api
.controller('signupCtrl', function($scope,$http,$ionicPopup,$state,$ionicHistory) {
$scope.signup=function(data){
var link = 'http://xxxxxxxxxxxxxxxxxxxxxx/api/Home/RegisterUser';
//using http post
//passing values to parameter
$http.post(link, {RegisterName : data.name, RegisterUserName : data.username, RegisterPassword : data.password , RegisterEmail: data.mail , RegisterMobile : data.mobile})
.then(function (res){ //if a response is recieved from the server.
$scope.response = res; //contains Register Result
console.log($scope.response);
});
}
})
With the above code I am getting following result in google chrome console
I am try to get that status only to match it value but I am unable to do so.
The doubt I am having is that json format
console.log(JSON.stringify($scope.response)) will do what you need.
If you're wanting those particular value, you can just access those and pass them to log.
console.log($scope.response.data['status']);
you get the json as :
$scope.response = res.data;
might be you require JSON.parse(res.data) or $.parseJSON(res.data) for getting json object
How can I add a new document to Content Server 10.5 using the REST api?
I am following the Swagger docs for creating a node, but it is not clear how I attach the file to the request. Here is (roughly) the code I am using:
var folderId = 2000;
var docName = "test";
var uri = $"http://[serverName]/otcs/llisapi.dll/api/v1/nodes?type=144&parent_id={folderId}&name={docName}";
var request = new HttpRequestMessage();
request.Headers.Add("Connection", new[] { "Keep-Alive" });
request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
request.Headers.Add("Pragma", "no-cache");
request.Headers.Add("OTCSTicket", /* ticket here */);
request.RequestUri = new Uri(uri);
request.Method = HttpMethod.Post;
request.Content = new ByteArrayContent(data);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(filePath));
request.Headers.ExpectContinue = false;
var httpClientHandler = new HttpClientHandler
{
Proxy = WebRequest.GetSystemWebProxy(),
UseProxy = true,
AllowAutoRedirect = true
};
using (var client = new HttpClient(httpClientHandler))
{
var response = client.SendAsync(request).Result;
IEnumerable<string> temp;
var vals = response.Headers.TryGetValues("OTCSTicket", out temp) ? temp : new List<string>();
if (vals.Any())
{
this.ticket = vals.First();
}
return response.Content.ReadAsStringAsync().Result;
}
I've been searching through the developer.opentext.com forums, but finding a complete example in c# is proving tough - there are a few examples in javascript, but attempting to replicate these in c# or via chrome or firefox extensions just give the same results. Calling other CS REST methods has not been an issue so far, this is the first one that's giving me problems.
Edit: I pasted the wrong url into my question, which I've now fixed. It was var uri = $"http://[serverName]/otcs/llisapi.dll/api/v1/forms/nodes/create?type=0&parent_id={folderId}&name={docName}";.
Your URL doesn't look like the REST API, it's rather the traditional URL used for the UI.
This article should describe how to do what you want to do:
https://developer.opentext.com/webaccess/#url=%2Fawd%2Fresources%2Farticles%2F6102%2Fcontent%2Bserver%2Brest%2Bapi%2B%2Bquick%2Bstart%2Bguide&tab=501
EDITED:
Ok, so that's how it should work:
send a POST to http://www.your_content_server.com/cs[.exe]/api/v1/nodes
send this in your payload to create a document in your enterprise workspace
type=144
parent_id=2000
name=document_name.txt
<file>
A incomplete demo in Python would look like this. Make sure you get a valid ticket first.
files = {'file': (open("file.txt", 'rb')}
data = { 'type': 144, 'parent_id': 2000, 'name': 'document_name.txt' }
cs = requests.post(url, headers={'otcsticket':'xxxxxxx'}, data=data, files=files)
if cs.status_code == 200:
print "ok"
else:
print cs.text
You will need a form input to get the file onto the page then you can use filestreams to redirect it, there is great guide for that here.
Reading files in JavaScript using the File APIs
Here is a Jquery/ Ajax example.
I find the best way to go about this is to use Postman (Chrome Plugin) to experiment until you get comfortable.
var form = new FormData();
form.append("file", "*filestream*");
form.append("parent_id", "100000");
form.append("name", "NameYourCreatedFile");
form.append("type", "144");
var settings = {
"async": true,
"url": "/cs.exe/api/v1/nodes", // You will need to amend this to match your environment
"method": "POST",
"headers": {
"authorization": "Basic **use Postman to generate this**",
"cache-control": "no-cache",
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
$.ajax(settings).done(function (response) {
console.log(response);
});
It appears that the OpenText API only supports file uploads through asynchronous JavaScript uploads - not through traditional file uploads by using typical posted form requests that contain the files contents (which is pretty crappy to be honest - as this would be the easiest to handle on server side).
I've contacted their support and they were absolutely no help - they said since it's working with JavaScript, then they can't help me. Anyone else utilizing any language besides JavaScript is SOL. I submitted my entire API package, but they didn't bother investigating and wanted to close my ticket ASAP.
The only way I've found to do this, is to upload / send the file into your 'Upload' directory on your Content Servers web server (on ours it was set to D:\Upload).This directory location is configurable in the admin section.
Once you've sent the file to your web server, send a create node request with the file param set to the full file path of the file residing on your server, as the OpenText API will attempt to retrieve the file from this directory.
I've created a PHP API for this, and you can browse its usage here:
https://github.com/FBCLIT/OpenTextApi
<?php
use Fbcl\OpenTextApi\Client;
$client = new Client('http://server.com/otcs/cs.exe', 'v1');
$api = $client->connect('username', 'secret');
try {
// The folder node ID of where the file will be created under.
$parentNodeId = '12356';
// The file name to display in OpenText
$fileName = 'My Document.txt';
// The actual file path of the file on the OpenText server.
$serverFilePath = 'D:\Upload\My Document.txt';
$response = $api->createNodeDocument($parentNodeId, $fileName, $serverFilePath);
if (isset($response['id'])) {
// The ID of the newly created document will be returned.
echo $response['id'];
}
} catch (\Exception $ex) {
// File not found on server drive, or issue creating node from given parent.
}
MIME Type detection appears to happen automatically, and you do not need to send anything for it to detect the file type. You can name the file to whatever you like without an extension.
I have also discovered that you cannot use an IP address or Host name for uploading files in this manor. You must enter a path that is local to the server you are uploading to. You can however give just the file name that exists in the Upload directory, and the OpenText API seems to locate it fine.
For example, you can pass either D:\Uploads\Document.txt or Document.txt.
If you haven't done it correctly, you should get the error:
Client error: POST http://server.com/otcs/cs.exe/api/v1/nodes resulted in a 400 Bad Request response: {"error":"Error: File could not be found within the upload directory."}
I've looked around at other questions but they don't seem to fully answer this question, I'm trying to pass an object via JSON to the client Javascript. I'm using Newtonsoft.Json to make the process easier, but I can't seem to recieve the object.
Here's the code:
When a connection is made, I call the Hub using start().done() in the client javascript:
//start comm with server
$.connection.hub.start().done(function () {
console.log('Grabbing playlist data');
Playlist.server.requestPlaylist();
});
This calls the following method, which is supposed to grab the object and pass it back:
public void requestPlaylist()
{
var playlistData = (from c in db.Playlist where c.ID > 0 select c).Include(h => h.Song).ToList();
Playlist player = new Playlist();
foreach (var item in playlistData)
{
player.ID = item.ID;
player.Profile = item.Profile;
player.Song.ID = item.Song.ID;
player.Song.name = item.Song.name;
player.upvotes = item.upvotes;
}
string jsonObject = JsonConvert.SerializeObject(player);
Clients.All.recievePlaylist(jsonObject);
}
SO here, I'm searching the database, getting the results and storing it into the playlist model, then using newtonsoft.json to convert the model into a json object (Its roughly the same principle they have as an example on their site).
The client javascript that is invoked from this is:
function recievePlaylist(jsonObject) {
console.log('test to recieve data: ' + jsonObject.ID + ' test.');
};
Now just for testing purposes I'm just logging out out to the console, but this come back with nothing:
"test to recieve data: test." is how it comes back.
What am I missing?
Because you convert the object to a string on the server before passing it to the client, the client receives a string. Your string representation of a json object doesnt have an ID property so the value will be "undefined".
On the client you can use this to convert the string to a json object:
jsonObject = JSON.parse(jsonObject);
Just add that line to the top of your recievePlaylist function.
Note: You shouldn't actually need to convert your server object to a json string on the server side. SignalR automatically converts your server side objects to json objects on the client.
If you call WebAPI and receive json response/result on client side (JavaScript/jQuery). The way is general for both SignalR or WebAPI in regards of parse jsone response and the use it as object.
var obj = jQuery.parseJSON( '{ "name": "John" }' );
alert( obj.name === "John" );
I have a problem passing a large JSON string to a web service from the client side with a jQuery function. When the lenth of the string increases to 1000 characters, the web service throw an exception "Unspecified Network Error". Please let me know how to pass a large JSON value to a web service using [webinvoke].
Can we increase the size of url or whatever to fix this problem?
You can serialize your Json as object:
page.asp
var data1 = {
IdTest: ('<%= miAspVar %>'),
fono: telefono,
etc, etc
};
var strData = YAHOO.lang.JSON.stringify(data1)
callService(testLlamada, strData, EstadoLlamada, onError2);
function onError2(result) {
alert(result);
}
function EstadoLlamada(result) {
...
}