T1C-JS Guide (v2)
v2.4.1
Search…
⌃K

Citrix

Introduction

In a Citrix environment, there is one Trust1Connector core service, running on the main machine, and one or more agents, one for each user session, which registers itself on the core service. The core service then acts as a proxy, relaying requests to specific agents as needed.
When running in Citrix mode (citrix === true in the configuration), the core Trust1Connector service will not allow access to any endpoint other than the agent list.
In order to communicate with an agent, we must determine which agent we want to use (this is up to the application), and then re-initialize a client library with the agentPort of our target agent. This will redirect all requests to this agent.

Configuration

If your Trust1Connector package has Citrix capabilities, you can en- or disable this.
In order to enable Citrix, you must take the following steps (administrator rights are required):
  • Stop the Trust1Connector service (Windows services, launchctl on macOS).
  • Edit the t1c_config.json configuration file with citrix.enabled = true (see Locations to find the t1c_config.json file).
  • Restart the machine.
  • The service and the Citrix agent will automatically start at login of the user.
To disable, follow the same steps but set citrix.enabled = false.

Flow

Retrieving agent list

The agent list is managed by the core Trust1Connector service, and is the only endpoint that is accessible on this instance of Trust1Connector.
To retrieve the list, we initialize a GCLClient instance without agent port, which will communicate directly with the core T1C.
var config = new GCLConfig();
GCLLib.GCLClient.initialize(config, function(err, client) {
// client returned is initialized for use with the core Trust1Connector
// can only be used for retrieving agent list
});
The following code is a small example of how to generate an invisible clipboard action. This can be used to generate the challenge which is used in the following step -- resolveAgent
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
let challenge = localStorage.getItem("t1c-challenge")
if(!localStorage.getItem("t1c-challenge")) {
challenge = makeid(10);
}
copyToClipboard(challenge);
Once this is done, we can retrieve the agent list:
// The challenge proprty is created by doing a clipboard action.
client.admin().resolveAgent(challenge).then(result=> {
// result contains the full list of agents
});
A typical result looks like this:
{ "data": [{
"hostname": "hostname",
"last_update": "2017-09-01T00:00:00.000000",
"metadata": {},
"port": 56789,
"username": "username"
}],
"success":true }
It contains an array of all the agents known to the system. It is also possible to filter the list of results, by passing in a filter object:
client.agent().get({ username: 'username' }).then(result => {
// result contains only agents matching the username
});
The filters will be matched to the username and metadata properties of the agents, and only matching agents will be returned.
Once the list of agents is retrieved, the application selects the agent to use from the list. For this agent, we initialize a new client that will communicate only with the selected client by passing in the port in our config.

Initialize agent client

Once we have determined the agent port to use, we can initialize the agent client as follows:
var agentPort = 56789 // example agent port
var config = new GCLConfig();
config.agentPort = agentPort;
GCLLib.GCLClient.initialize(config, function(err, client) {
// client returned is initialized for use with the agent on port 56789
// should be used for all subsequent calls
});
The new client will now only communicate with the selected agent, and should be used for all subsequent calls.