Smart card selection for digital signature - javascript

I am mantaining a VB6 Windows application which digitally signs PDF documents by launching a JS file, located in the Javascripts subfolder of Acrobat 9.0. Now my Customer wants to plug another smart card reader to the PC which hosts the application, with its own smart card containing certificates related to a second person who will sign certain type of documents.
My question is: how can I programmatically choose, from my JavaScript code, the smart card reader I want?
In my JavaScript code I do the following:
//Initialize the signature handler
var myEngine = security.getHandler("Adobe.PPKLite");
//Obtain the available certificates
var ids = myEngine.digitalIDs;
var myCerts = ids.certs;
//Find the certificate I want to use to sign
for(var j=0; j<myCerts.length; j++)
{
if(myCerts[j].subjectCN == "SMITH JOHN")
{
oCert = myCerts[j];
break;
}
}
//Log to the signature engine by passing the certificate I want to use
//and the slot where the corresponding smart card reader is plugged
myEngine.login( { oParams: { cDIPath: ACROSDK.sigDigitalIDPath,
cPassword: ACROSDK.sigUserPwd,
iSlotID: 1,
oEndUserSignCert: oCert
}
} );
//Digitally sign the document with the certificate I chose
sigField.signatureSign({oSig: myEngine,
bUI: false,
oInfo: { password: ACROSDK.sigUserPwd,
location: ACROSDK.sigLocation,
reason: ACROSDK.sigReason,
contactInfo: ACROSDK.sigContactInfo,
appearance: "FirmaRPPR"
}
});
Why do I receive a General Error when executing signatureSign? Which is the correct way to assign the iSlotID parameter when logging to the signature engine or, alternatively, the cTokenLabel parameter?
Thanks in advance for your help and suggestions!

Mind you, I have no experience in using Acrobat scripting, but in PKCS#11 slot id would refer to the id of the smart card reader connected to the computer, and token label would be assigned label to one of the smart carts in that slot/reader, which can vary from PKCS#11 implementation to another.
And the easiest way to find out the label of the PKCS#11 token would be to configure the PKCS#11 DLL you're using as a Security device in Firefox browser and see the label field in the configuration. But that would be just to get you going in the right direction.
You can write a short C program against the PKCS#11 and use C_GetSlotList and C_GetSlotInfo to find out the slot id's and token labels, here is an example of that. It should not be a problem to port that code over to VB. Also there is NCryptoki that you can use to interface the PKCS#11 DLL.

Related

Error when running Youtube Data Service in App Scripts (js) – Daily Limit for Unauthenticated Use Exceeded

I'm running a custom function in App Scripts which utilizes the Youtube (YouTube Data API v3) advanced service. When running, I get the following error:
GoogleJsonResponseException: API call to youtube.videos.list failed with error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. (line 15).
I'm not sure how to authenticate my application. I've added it to a cloud project and enabled the API's.
Update: Here's what my code looks like:
function getYoutubeData(youtubeId) {
// Don't run on empty
if(!youtubeId){return null}
// Make the request
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return null}
// Get the first item
vidData = vidData[0];
return vidData.statistics
}
I believe your goal as follows.
You want to put the value of vidData.statistics in your script to the cell.
You want to achieve this using custom function like =getYoutubeData(youtubeId).
For this, how about this answer?
Issue and workaround:
Unfortunately, when YouTube Data API of Advanced Google services is used in the custom function, the access token is not used. From your script, I think that the reason of your issue is this. For example, when the function of const sample = () => ScriptApp.getOAuthToken(); is used as the custom function like =sample(), no value is returned. I think that this is the current specification of Google side because of the security.
In order to achieve your goal under above situation, how about the following workarounds?
Workaround 1:
In this workaround, at first, the youtube ID is set to the cells in Google Spreadsheet. And the value of vidData.statistics are retrieved by the Google Apps Script which is not the custom function and replace the youtube ID with the result values.
Sample script:
Please set the range of cells of youtube IDs to sourceRange and the sheet name. At the sample, it supposes that the youtube IDs are put to the cells "A1:A10". And please run getYoutubeData() at the script editor. Of course, you can also set this to the custom menu.
function getYoutubeData() {
const sourceRange = "A1:A10"; // Please set the range of cells of youtube IDs.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the sheet name.
const range = sheet.getRange(sourceRange);
const youtubeIds = range.getValues();
const values = youtubeIds.map(([youtubeId]) => {
// This is your script.
if(!youtubeId){return [null]}
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return [null]}
vidData = vidData[0];
return [JSON.stringify(vidData.statistics)];
});
range.setValues(values);
}
Workaround 2:
In this workaround, the custom function is used. But, in this case, the Web Apps is used as the wrapper. By this, the authorization process is done at the Web Apps. So the custom function can be run without the authorization. Please do the following flow.
1. Prepare script.
When your script is used, it becomes as follows. Please copy and paste the following script to the script editor.
Sample script:
// This is your script.
function getYoutubeData_forWebApps(youtubeId) {
// Don't run on empty
if(!youtubeId){return null}
// Make the request
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return null}
// Get the first item
vidData = vidData[0];
return vidData.statistics
}
// Web Apps using as the wrapper.
function doGet(e) {
const res = getYoutubeData_forWebApps(e.parameter.youtubeId)
return ContentService.createTextOutput(JSON.stringify(res));
}
// This is used as the custom function.
function getYoutubeData(youtubeId) {
const url = "https://script.google.com/macros/s/###/exec?youtubeId=" + youtubeId; // Please set the URL of Web Apps after you set the Web Apps.
return UrlFetchApp.fetch(url).getContentText();
}
2. Deploy Web Apps.
On the script editor, Open a dialog box by "Publish" -> "Deploy as web app".
Select "Me" for "Execute the app as:".
By this, the script is run as the owner.
Select "Anyone, even anonymous" for "Who has access to the app:".
In this case, no access token is required to be request. I think that I recommend this setting for testing this workaround.
Of course, you can also use the access token. But, in this case, when the access token is used, this sample script cannot be directly used as the custom function.
Click "Deploy" button as new "Project version".
Automatically open a dialog box of "Authorization required".
Click "Review Permissions".
Select own account.
Click "Advanced" at "This app isn't verified".
Click "Go to ### project name ###(unsafe)"
Click "Allow" button.
Click "OK".
Copy the URL of Web Apps. It's like https://script.google.com/macros/s/###/exec.
When you modified the Google Apps Script, please redeploy as new version. By this, the modified script is reflected to Web Apps. Please be careful this.
Please set the URL of https://script.google.com/macros/s/###/exec to url of above script. And please redeploy Web Apps. By this, the latest script is reflected to the Web Apps. So please be careful this.
4. Test this workaround.
Please put =getYoutubeData("###youtubeId###") to a cell. By this, the youtube ID is sent to the Web Apps and the Web Apps returns the values of vidData.statistics.
Note:
These are the simple sample scripts for explaining the workarounds. So when you use this, please modify it for your actual situation.
References:
Custom Functions in Google Sheets
Web Apps
Taking advantage of Web Apps with Google Apps Script

LaunchDarkly Bootstrapping: (JS) Property Assignment Expected

I am setting up LaunchDarkly to control my first feature flag and its working fine from server & client side.
Now I am trying LaunchDarkly Bootstrap approach (From the below given Link) and tried like below my code, but it's not accepting the double braces and I do not know How to get flag value by using the bootstrap approach, so where I did go wrong in my code?. Could anyone please help me with an example?
Link,
https://docs.launchdarkly.com/docs/js-sdk-reference#section-bootstrapping
Initialized client with Bootstrap option as below,
client = LDClient.initialize(sdkKey, userContext.user, options = {
bootstrap: {
{{ ldclient.all_flags(userContext.user) }}
}
});
And my function to get the flag value,
isFeatureEnabled: function (featureFlag, properties) {
console.log("Before Variation");
//we shall update the custom properties into user context.
if (properties) {
for (var k in properties) {
userContext.user.custom[k] = properties[k];
}
}
//later make the identity call to update the user details.
client.identify(userContext.user, null, function () { /*rules updated*/
console.log("New user's flags available");
//validate the feature flag
var showFeature = client.variation(featureFlag);
if (!showFeature) {
window.in8.platform.showUnauthorized('');
}
console.log("after Variation");
});
}
Full disclosure, My name is John, and I am part of the support team here at LaunchDarkly. I'll be happy to help you out with this problem
Firstly, it appears you are using an older version of the bootstrapping example. The new example has a typo fix, and uses the new all_flags_state method.
I see two major issues here. There is the primary issue of how to bootstrap flag variations from the back-end to the front-end, and how to appropriately utilize LaunchDarkly when using bootstrapping. I will tackle the issue of how to bootstrap flag variations from the back-end first.
The example in LaunchDarkly's documentation utilizes templating to include the bootstrapped values to the front end. Templating is a strategy for including programmatically generated content in your static source or text files. Templating is commonly used when compiling or deploying code, or at runtime when serving content to clients. This is done to render information only available at that time in the final version.
Different templating languages behave in different ways, but generally speaking you include tokens in your source or text files which direct the template renderer to replace that token with data you supply it.
In the documentation it mentions that this example is for templating using Ruby, but the example is using Mustache rendering, and Mustache is available in many different languages. Templating is a strategy for including programmatically generated content in your static source or text files. This is commonly used when compiling or deploying code, or at runtime when serving content to clients. This is done to render information only available at that time in the final version.
The example may not work depending on which back-end language and framework you are using. According to the tags associated with your question, I feel safe to assume that you are using .NET to power your back-end, which doesn't have a prescribed templating language. There are many open source solutions out there, though.
In the following example I'm going to use https://github.com/rexm/Handlebars.Net to render the a users bootstrapped flag values into the result variable. I am going to borrow code available from the example in the handle bars repo, and from LaunchDarkly's hello-bootstrap and hello-dotnet repos, which are available here: https://github.com/launchdarkly/hello-bootstrap & https://github.com/launchdarkly/hello-dotnet
string source =
#"
<html>
<head>
<script src=""https://app.launchdarkly.com/snippet/ldclient.min.js""></script>
<script>
window.ldBootstrap={{ldBootstrap}};
window.ldClientsideId=""{{ldClientsideId}}"";
window.ldUser={{ldUser}};
</script>
</head>
<body>
<h1>LaunchDarkly server-side bootstrap example</h1>
<ul>
<li><code>normal client</code>: <span class=""normal"">initializing…</span></li>
<li><code>bootstrapped client</code>: <span class=""bootstrap"">initializing…</span></li>
</ul>
<script>
var user = window.ldUser;
console.log(`Clients initialized`);
var client = LDClient.initialize(window.ldClientsideId, user);
var bootstrapClient = LDClient.initialize(window.ldClientsideId, user, {
bootstrap: window.ldBootstrap
});
client.on('ready', handleUpdateNormalClient);
client.on('change', handleUpdateNormalClient);
bootstrapClient.on('ready', handleUpdateBootstrapClient);
bootstrapClient.on('change', handleUpdateBootstrapClient);
function handleUpdateNormalClient(){
console.log(`Normal SDK updated`);
render('.normal', client);
}
function handleUpdateBootstrapClient(){
console.log(`Bootstrapped SDK updated`);
render('.bootstrap', bootstrapClient);
}
function render(selector, targetClient) {
document.querySelector(selector).innerHTML = JSON.stringify(targetClient.allFlags(user), null, 2);
}
</script>
</body>
</html>";
var template = Handlebars.Compile(source);
Configuration ldConfig = LaunchDarkly.Client.Configuration.Default("YOUR_SDK_KEY");
LdClient client = new LdClient(ldConfig);
User user = User.WithKey("bob#example.com")
.AndFirstName("Bob")
.AndLastName("Loblaw")
.AndCustomAttribute("groups", "beta_testers");
var data = new {
ldBootstrap: JsonConvert.SerializeObject(client.AllFlagsState(user)),
ldUser = JsonConvert.SerializeObject(user),
ldClientsideId = "YOUR_CLIENT_SIDE_ID"
};
var result = template(data);
You could take this example and adapt it to render your static source code when serving the page to your users.
The second issue is how you are utilizing the SDK. I see that you are calling identify before evaluating your user every time. Each time you call identify the SDK needs to reinitialize. This means that even after bootstrapping your initial variations you will force the SDK to reinitialize by calling identify, removing all benefits of bootstrapping. As a solution, detect if your user object has changed. if it has, then call identify. Otherwise, do not call identify so that the SDK uses the cached user attributes.
If you want to dive deeper into this and provide us with some more of the source for your wrapper you can reach out to us at support#launchdarkly.com

Is it possible to send a key code to an application that is not in front?

I'm writing a simple Automator script in Javascript.
I want to send a key-code(or key-storke) to an OS X application that is not in front.
Basically, I want to run this code and do my things while the script opens a certain application, write text, and hit enter - all of this without bothering my other work.
I want something like this:
Application("System Events").processes['someApp'].windows[0].textFields[0].keyCode(76);
In Script Dictionary, there is keyCode method under Processes Suite.
The above code, however, throws an error that follows:
execution error: Error on line 16: Error: Named parameters must be passed as an object. (-2700)
I understand that the following code works fine, but it require the application to be running in front:
// KeyCode 76 => "Enter"
Application("System Events").keyCode(76);
UPDATE: I'm trying to search something on iTunes(Apple Music). Is this possible without bringing iTunes app upfront?
It's possible to write text in application that is not in front with the help of the GUI Scripting (accessibility), but :
You need to know what UI elements are in the window of your specific
application, and to know the attributes and properties of the
specific element.
You need to add your script in the System Preferences --> Security
& Privacy --> Accessibility.
Here's a sample script (tested on macOS Sierra) to write some text at the position of the cursor in the front document of the "TextEdit" application.
Application("System Events").processes['TextEdit'].windows[0].scrollAreas[0].textAreas[0].attributes["AXSelectedText"].value = "some text" + "\r" // r is the return KEY
Update
To send some key code to a background application, you can use the CGEventPostToPid() method of the Carbon framework.
Here's the script to search some text in iTunes (Works on my computer, macOS Sierra and iTunes Version 10.6.2).
ObjC.import('Carbon')
iPid = Application("System Events").processes['iTunes'].unixId()
searchField = Application("System Events").processes['iTunes'].windows[0].textFields[0]
searchField.buttons[0].actions['AXPress'].perform()
delay(0.1) // increase it, if no search
searchField.focused = true
delay(0.3) // increase it, if no search
searchField.value = "world" // the searching text
searchField.actions["AXConfirm"].perform()
delay(0.1) // increase it, if no search
// ** carbon methods to send the enter key to a background application ***
enterDown = $.CGEventCreateKeyboardEvent($(), 76, true);
enterUp = $.CGEventCreateKeyboardEvent($(), 76, false);
$.CGEventPostToPid(iPid, enterDown);
delay(0.1)
$.CGEventPostToPid(iPid, enterUp);

Issuing MySQL queries from standalone Javascript (no, I'm not crazy, my vendor is)

Our lab recently got an Agilent Bravo pipetting robot (it precisely dispenses tiny quantities of liquid for doing rapidly doing many biology or chemistry experiments). Apparently the glue language for extending the software that controls the robot is Javascript! I know, right?
Anyway, for the robot to be useful, we have to be able to retrieve information about the samples it's handling but every example I can find for sending queries in Javascript depends on PHP and usually the assumption that the script is running in a web-browser.
Is there some way to wrap a command-line mysql or is there already some library or utility that does this? The OS we're running is Windows 7.
Wow, thanks for the quick and useful answers.
In addition, I found a platform-specific answer: http://www.velocity11.com/techdocs/helpsystem/vworks_ug/usingjavascriptinvworks.html
Long story short, VWorks (control software for Agilent's equipment) has a run() global function that does exactly that. But, the above answers are probably more useful to this site than my own is, because they are relevant to a broader range of problems, so thanks again.
"sending queries in Javascript depends on PHP"
no it doesn't.
Just send retreive data(json) using ajax, I'd use http://api.jquery.com/jQuery.ajax/.
Yes, you can use ADO with Javascript on Windows to access various data sources. Search for "jscript ado" and you will get lots of information on this, e.g.:
// path to database
var DBpath="\\\\Server\\Path\\myDB.mdb"
// set up a few object constants
var adLockReadOnly=1
var adOpenForwardOnly=0
var adCmdText=1
// create and open a new connection (MSAccess)
var cnn=new ActiveXObject("ADODB.connection")
cnn.Provider = "Microsoft.Jet.OLEDB.4.0;Data Source=" + DBpath
try
{
cnn.open
}
catch(err)
{
// could not open connection
// view details in err.Description and err.Number
return 0
}
//open a read only recordset
var rs = new ActiveXObject("ADODB.Recordset")
try
{
rs.Open("Select * from myTable", cnn, adOpenForwardOnly, adLockReadOnly)
}
catch(err)
{
// could not open recordset
return 0
}
while(!rs.EOF)
{
// do something
rs.movenext
}
rs.close
Update:
According to info here, you can develop plugins using Visual Studio/C#. Maybe that is of some use? You could write a plugin to send the data somewhere...

How to use Javascript to check active directory to see if a user is in a memberof a particular group?

I have at my disposal Javascript and Classic ASP. Using these two how can I check to see if a user is a member of a particular active directory group? I know VBSCRIPT has memberof function but I can only use javascript. Any help is appreciated
You'll need to ensure that your web server is set to use Windows Authentication. Then you can use Request.ServerVariables("LOGON_USER") to get the current user's domain\username.
You'll then query Active Directory using ADSI to get group membership.
Here's a link to msdn's ADSI pages. http://msdn.microsoft.com/en-us/library/aa772170%28v=vs.85%29.aspx
This page has some sample scripts (in vbscript)
As far as I know there is no possibility to access activeDirectory by using Javascript. Javascript runs within the browser - and may not access anything out of this sandbox.
In case I misunderstood your question und you ment server-side checking - use ASP functions to check for.
You might also try using Javascript to instantialte a WScript.Network object
var WshNetwork = new ActiveXObject("WScript.Network");
From there, you can get
var netWorkUserName = WshNetwork.UserName;
var netWorkDomain = WshNetwork.UserDomain;
A word of warning: I'm pretty sure this is IE only and requires security changes in IE.
You'll need AJAX and a connection to the AD using ADODB.Connection with the "ADsDSOObject" provider.
EDIT: I saw your comment above. Here's a start:
ldapCommand.CommandText = "select sn from '" & _
"LDAP://example.com/DC=example,DC=com" & _
"' WHERE samAccountName=" & "'" & username & "'"
Set ldapRecordSet = ldapCommand.Execute
ldapCommand is an ADODB.Command, and if Execute throws an error, then the user is not in the domain.

Categories

Resources