Why You Need to Sign Your Custom Code

Thursday, November 27, 2014 by Alexander Huber
Image source: https://flic.kr/p/6UKyJq, under Creative Commons License

Those of you who use time cockpit’s browser version might have run into the following problem: You open a list, try to execute an action or simply try to save a time sheet entry and time cockpit shows the following message: Hash could not be verified. Agreed, the message might sound a bit scary and technical. However, this message does not indicate an error. Actuallyit is a security feature of time cockpit kicking in. Before we talk about the actual message, we would like to describe the context in which the message is presented to a user.

Python Scripts in Time Cockpit

One of time cockpit’s unique selling propositions is that it is heavily customizable. Here are some examples:

  • Change and extend time cockpit's data model to you specific needs. You can e.g. create new entities, add properties, and add relations to the entities.
  • To enforce business rules you can create validation rules using time cockpit's expression language.
  • If you would like to restrict access to certain resources in time cockpit you can define permission rules.
  • You can even create custom UI elements, lists and forms.

All of these change can be done without programming in a language like C# or Python. For most people, these customization mechanisms will suffice. However, for even more advanced customization scenarios our customers can use time cockpit's built-in scripting language Iron Python. Time cockpit supports the use of script for

  1. Lists and reports,
  2. Actions, and
  3. Triggers.

Lists and Reports

For classical lists you need to specify a single TCQL query that fetches the data records that should be displayed. However, there are scenarios where a single query as a data source is not enough. In such cases, time cockpit uses so called script source lists: Lists where a small Python script acts as the data source.

On the one hand, the definition of a script source list is more complex than a common list. On the other hand it provides much more flexibility. If you want to e.g. combine the results of two different TCQL queries (e.g. combine timesheet and vacation data in a single report), you need to use a script source list. Also, if you need to perform operations that are not available in TCQL (e.g. custom aggregations), script source lists are needed.

<List AllowDelete="True" AllowEdit="True" EditModelEntityName="APP_Vacation" EditProperty="VacationUuid" xmlns="clr-namespace:TimeCockpit.Data.DataModel.View;assembly=TimeCockpit.Data" xmlns:p="http://www.timecockpit.com/2009/ui/controls" xmlns:sys="clr-namespace:System;assembly=mscorlib">
	<List.ScriptSource>
		<sys:String xml:space="preserve">
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)

def getResultModelEntity(context):
	entity = ModelEntity({ "Name": "Result" })
	entity.Properties.Add(GuidProperty({ "Name": "VacationUuid" }))
	...	
	return entity

def getItems(context, queryParameters):
	clr.AddReference("TimeCockpit.Programmability")
	from TimeCockpit.Programmability.Functions import Constants
	from System import Version, String
	version = clr.GetClrType(Constants).Assembly.GetName().Version
	recent = (version >= Version(1, 18, 0, 0) or version == Version(0, 0, 0, 0))

	# fetch data from DB
	
	return vacation.Concat(vacationEntitlement).OrderBy(lambda t: t.EndTime).Cast[EntityObject]()
   
# SIG 77619404EF9B1418136698A70545893B739EB6C3 n5gegpq6s43qGYsIIUhEcU7ONwtbsY85dJHrrR80E/2vtgEdtt3CSnjOtd2BXdQFvFiquQMYheDXxyIAQ96R3rsdH5Xd6ccqYdgs1ZNeqQBsUrDuiHLKjYZ1h+9Js9+hWBqwRKLUd/WQTDO0JNq8r7vqwurfunU1BkMVmkdj4V+67rpJgjt4fBOcngKzT36ZUyAoSDu9EgrtSEmttxilH26TRT7CQTydnqVVzuQGvD0SB4hO4cM+6O94lXPgqj3LSAQt7me/4oC6+WH/553WBZYC88oIAytFakkHsolvBjBx/6frFU0xyDMgeRcB6O+tjCfXVXUMk7ps5VvDObGOgA==</sys:String>
	</List.ScriptSource>
	<BoundCell Content="=Current.UserDetailName" Header="=:FriendlyName('APP_UserDetail')" />
	...
</List>

As you can see in the above source code, the list does not have an <List.Query> tag, but a <List.ScriptSource> tag. The tag contains the Iron Python code the fetches data and prepares it for presentation in the list. It is important to note two methods in the source code:

  1. getItems Method: The getItems method does the heavily lifting of a script source list. It connects to the time cockpit data context, prepares the result, and hands it back to the list rendering engine of time cockpit.
  2. getResultModelEntity Method:  The getResultModelEntity method is new in this month's version of time cockpit and plays an important role especially for the web client. The method provides information about the data model of the results of the getItems method. 

Although script source lists without getResultModelEntity will work in time cockpit's full client, the presence of the method is a prerequisite to use the script source list in time cockpit's upcoming HTML-based web client.

If you have existing script source lists in your time cockpit account, contact us at support@timecockpit.com and we will provide guidance on how to implement the getResultModelEntity method. You can also read more about defining time cockpit data models in scripts in the online help.

If you are interested in a complete sample of a script source list, take a look at the APP_DefaultVacationList in your time cockpit's Customization module. 

Actions

In contrast to lists, actions can not only read data, they can also manipulate it. Actions are typically used to implement customer-specific business logic. Like data, actions are deployed to the time cockpit clients time cockpit’s sync mechanism. Therefore, time cockpit automatically cares for rolling out new version of Actions. For an example for actions see the Actions topic in our online documentation.

Triggers

Triggers are an advanced concept of time cockpit. Like triggers in a database, triggers in time cockpit are executed whenever a record (e.g. a time sheet) is inserted, updated, and/or deleted. Triggers are not configurable via the time cockpit customization interface. You can only create triggers via scripting. They are a very powerful concept and describing them here would exceed the scope of this article. Triggers would deserve their own blog article. Until then, if you are interested in triggers, drop us a mail at support@timecockpit.com and we will tell you more about them. 

User Code in a Hosted Environment

Now what has all that to do with the message “Hash could not be verified”? As we have learned above, users of time cockpit can define lists, actions, and triggers that run user-defined source code. If you are using the full client, the script code runs on the machine of the user. The script can potentially harm only your own PC that is executing the code.

However, if you use the browser client (Silverlight or upcoming HTML version), user-defined source code runs on our shared infrastructure hosted in Microsoft Azure. We are responsible that script code of one customer does not degrade the time cockpit experience for other customers. Thus, we decided that user-defined scripts in lists, actions and triggers need to be validated and signed with a certificate that belongs to us.

Let us take a closer look at the script source list from above:

<List AllowDelete="True" AllowEdit="True" EditModelEntityName="APP_Vacation" EditProperty="VacationUuid" xmlns="clr-namespace:TimeCockpit.Data.DataModel.View;assembly=TimeCockpit.Data" xmlns:p="http://www.timecockpit.com/2009/ui/controls" xmlns:sys="clr-namespace:System;assembly=mscorlib">
	<List.ScriptSource>
		<sys:String xml:space="preserve">
...
   
# SIG 77619404EF9B1418136698A70545893B739EB6C3 n5gegpq6s43qGYsIIUhEcU7ONwtbsY85dJHrrR80E/2vtgEdtt3CSnjOtd2BXdQFvFiquQMYheDXxyIAQ96R3rsdH5Xd6ccqYdgs1ZNeqQBsUrDuiHLKjYZ1h+9Js9+hWBqwRKLUd/WQTDO0JNq8r7vqwurfunU1BkMVmkdj4V+67rpJgjt4fBOcngKzT36ZUyAoSDu9EgrtSEmttxilH26TRT7CQTydnqVVzuQGvD0SB4hO4cM+6O94lXPgqj3LSAQt7me/4oC6+WH/553WBZYC88oIAytFakkHsolvBjBx/6frFU0xyDMgeRcB6O+tjCfXVXUMk7ps5VvDObGOgA==</sys:String>
	</List.ScriptSource>
	...
</List>

The line that starts with # SIG contains the signature of the source code. Our signing mechanisms take the whole content of the <List.ScriptSource> tag and calculate a hash value from the script code. This hash value is used to verify that no one has tempered the code we validated and approved. If one adds so much as a whitespace somewhere in the script code, users will be presented the message “Hash could not be verified”. The same mechanisms also apply to Iron Python script code in actions and triggers.

I Want to have My Script Code Signed. What should I do?

If you have developed script source lists, actions, or triggers and you want them to work in time cockpit's browser client you need to send a signing request to support@timecockpit.com. We will get back to you, take a look at the source code, and check it for harmful or performance intensive operations. If the source code is OK from that point of view, we sign the script code with our certificate and you can use your script in your browser.

Note that no signing is required if you just want to use your script in time cockpit's full client.

Reviewing and signing of scripts is free of charge for time cockpit customers (fair-use policy applies). Depending on the size and the complexity of the script, veryfication and signing take between some minutes and some business hours.

comments powered by Disqus