Skip to content

Commit 6e93317

Browse files
committed
Added case sensitive support for getTypingPattern function. Optional usage.
1 parent 63beabf commit 6e93317

3 files changed

Lines changed: 1276 additions & 25 deletions

File tree

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
# TypingDNA JavaScript recorder
1+
# TypingDNA JavaScript recorder
22
##### A simple way to capture user’s typing patterns
33
Full documentation at [api.typingdna.com](https://api.typingdna.com)*
44

55
### Usage and description
6-
First you need to import the [typingdna.js](https://typingdna.com/scripts/typingdna.js) file in the page that wants to record a typing pattern. You will need to record typing patterns when a user first creates his account and again whenever you want to authenticate that user on your platform. You can host the .js file yourself.
6+
First you need to import the [typingdna.js](https://typingdna.com/scripts/typingdna.js) file in the page that wants to record a typing pattern. You will need to record typing patterns when a user first creates his account and again whenever you want to authenticate that user on your platform. You can host the .js file yourself.
77

8-
Alternative locations from where you can include the last class:
8+
Alternative locations from where you can include the last class:
99
* https://typingdna.com/scripts/typingdna.js
1010
* https://api.typingdna.com/scripts/typingdna.js
1111

1212
### TypingDNA class
1313

14-
Once you create an instance of the TypingDNA class, the user typing starts being recorded (as a history of strokes). Whenever you want to get the user's typing pattern you have to invoke .getTypingPattern method described in detail below.
14+
Once you create an instance of the TypingDNA class, the user typing starts being recorded (as a history of keystroke events). Whenever you want to get the user's typing pattern you have to invoke .getTypingPattern method described in detail below.
1515

1616
**Returns**: Returns the instance of the TypingDNA class (singleton)
1717

@@ -28,7 +28,7 @@ Here are the functions available in the TypingDNA class:
2828
* .start() *Automatically called by default*
2929
* .stop()
3030
* .reset()
31-
* .getQuality(typingPattern) ⇒ `Number`
31+
* .getQuality(typingPattern) ⇒ `Number`
3232

3333

3434
### TypingDNA.getTypingPattern(optionsObject)
@@ -38,14 +38,15 @@ This is the main function that outputs the user's typing pattern as a `String`
3838

3939
**optionsObject**: An object of the following form {type:Number, text:String, textId:Number, length: Number, extended:Boolean, targetId:String}. Detail table below.
4040

41-
| Param | Type | Description |
41+
| Param | Type | Description |
4242
| --- | --- | --- |
43-
| **type** | `Number` | `0 for anytext pattern` (when you compare random typed texts of usually 120-180 chars long) <br> `1 for diagram pattern` (recommended in most cases, for emails, passwords, phone numbers, credit cards, short texts) |
43+
| **type** | `Number` | `0 for anytext pattern` (when you compare random typed texts of usually 120-180 chars long) <br> `1 for diagram pattern` (recommended in most cases, for emails, passwords, phone numbers, credit cards, short texts) |
4444
| **text** | `String` | (Only for type 1) a typed string that you want the typing pattern for |
45-
| **textId** | `Number` | (Optional, only for type 1) a personalized id for the typed text |
45+
| **textId** | `Number` | (Optional, only for type 1) a personalized id for the typed text |
4646
| **length** | `Number` | (Optional) the length of the text in the history for which you want the typing pattern, for type 0 is usually 140 or more |
4747
| **extended** | `Boolean` | (Only for type 1) specifies if full information about what was typed is produced, including the actual key pressed, if false, only the order of pressed keys is kept (no actual content) |
4848
| **targetId** | `String` | (Optional) specifies if pattern is obtain only from text typed in a certain target |
49+
| **caseSensitive** | `Boolean` | (Optional, default: false, Only for type 1) Used if you pass a text for type 1 |
4950

5051
**Examples**
5152
```js
@@ -55,7 +56,7 @@ var generalPattern = tdna.getTypingPattern({type=0, length=160});
5556
```
5657

5758
### TypingDNA.addTarget(element_id)
58-
(Optional) Adds a target to the targetIds array. It has to be a text input or text area or any other HTML DOM element that has the .value property. You can add multiple targets (such as username and password fields).
59+
(Optional) Adds a target to the targetIds array. It has to be a text input or text area or any other HTML DOM element that has the .value property. You can add multiple targets (such as username and password fields).
5960

6061
If you omit adding targets the typing patterns will be recorded for the entire typing session.
6162

@@ -72,14 +73,14 @@ Remove a target from the targetIds array.
7273
Resets the history stack of recorded typing events.
7374

7475
### TypingDNA.start()
75-
Automatically called at initilization. It starts the recording of typing events. You only have to call .start() to resume recording after a .stop()
76+
Automatically called at initilization. It starts the recording of typing events. You only have to call .start() to resume recording after a .stop()
7677

7778
### TypingDNA.stop()
78-
Ends the recording of further typing events.
79+
Ends the recording of further typing events.
7980

8081
### TypingDNA.getQuality(typingPattern)
8182
Checks the quality of a general typing pattern (type 0), how well it is revelated, how useful the
82-
information will be for matching applications.
83+
information will be for matching applications.
8384

8485
**Returns**: `Number` - A real number between `0` and `1`. Values over `0.3` are acceptable, however a value over `0.7` shows good pattern strength.
8586

typingdna.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* https://api.typingdna.com/scripts/typingdna.js
44
* https://typingdna.com/scripts/typingdna.js (alternative)
55
*
6-
* @version 2.11
6+
* @version 2.12
77
* @author Raul Popa
88
* @copyright SC TypingDNA SRL, http://typingdna.com
99
* @license http://www.apache.org/licenses/LICENSE-2.0
@@ -102,7 +102,7 @@ function TypingDNA() {
102102
TypingDNA.prototype.defaultHistoryLength = TypingDNA.defaultHistoryLength;
103103
TypingDNA.prototype.maxSeekTime = TypingDNA.maxSeekTime;
104104
TypingDNA.prototype.maxPressTime = TypingDNA.maxPressTime;
105-
TypingDNA.version = 2.11;
105+
TypingDNA.version = 2.12;
106106
TypingDNA.flags = 0;
107107
TypingDNA.instance = this;
108108
TypingDNA.document = document;
@@ -631,6 +631,7 @@ function TypingDNA() {
631631
* * * @param {Boolean} extended (Only for type 1) specifies if full information about what was typed is produced,
632632
* * * including the actual key pressed, if false, only the order of pressed keys is kept (no actual content)
633633
* * * @param {String} targetId (Optional) specifies if pattern is obtain only from text typed in a certain target
634+
* * * @param {Boolean} caseSensitive (Optional, default: false, Only for type 1) Used if you pass a text for type 1
634635
* @return {String} A typing pattern in string form
635636
* @example var typingPattern = tdna.getTypingPattern({type=1, length=160, extended=true});
636637
* @example var typingPattern = tdna.getTypingPattern({type=1, text="Hello5g21?*", extedend=false});
@@ -644,9 +645,9 @@ function TypingDNA() {
644645
break;
645646
case 1:
646647
if (obj.text != undefined) {
647-
return TypingDNA.history.getDiagram(obj.extended, obj.text, obj.textId, obj.targetId);
648+
return TypingDNA.history.getDiagram(obj.extended, obj.text, obj.textId, obj.targetId, obj.caseSensitive);
648649
} else {
649-
return TypingDNA.history.getDiagram(obj.extended, obj.length, obj.textId, obj.targetId);
650+
return TypingDNA.history.getDiagram(obj.extended, obj.length, obj.textId, obj.targetId, obj.caseSensitive);
650651
}
651652
break;
652653
default:
@@ -659,11 +660,11 @@ function TypingDNA() {
659660
}
660661

661662
TypingDNA.getDiagram = function(str, textId) {
662-
return TypingDNA.history.getDiagram(false, str, textId);
663+
return TypingDNA.history.getDiagram(false, str, textId, undefined, false);
663664
}
664665

665666
TypingDNA.getExtendedDiagram = function(str, textId) {
666-
return TypingDNA.history.getDiagram(true, str, textId);
667+
return TypingDNA.history.getDiagram(true, str, textId, undefined, false);
667668
}
668669

669670
TypingDNA.getMouseDiagram = function() {
@@ -878,7 +879,8 @@ function TypingDNA() {
878879
this.stackDiagram.push(arr);
879880
}
880881

881-
TypingDNA.history.getDiagram = function(extended, str, textId, targetId) {
882+
TypingDNA.history.getDiagram = function(extended, str, textId, targetId, caseSensitive) {
883+
var caseSensitive = (caseSensitive != undefined) ? caseSensitive : (str == undefined || str == "");
882884
var returnArr = [];
883885
var diagramType = (extended == true) ? 1 : 0;
884886
var stackDiagram = this.stackDiagram;
@@ -908,7 +910,6 @@ function TypingDNA() {
908910
}
909911
}
910912
}
911-
912913
var missingCount = 0;
913914
var diagramHistoryLength = stackDiagram.length;
914915
var strLength = diagramHistoryLength;
@@ -917,7 +918,6 @@ function TypingDNA() {
917918
} else if (typeof str === 'number' && str < diagramHistoryLength) {
918919
strLength = str;
919920
}
920-
921921
var returnTextId = 0;
922922
if (textId != undefined) {
923923
if (isNaN(parseInt(textId))) {
@@ -930,21 +930,28 @@ function TypingDNA() {
930930
returnTextId = TypingDNA.math.fnv1aHash(str);
931931
}
932932
}
933-
934933
returnArr.push([TypingDNA.isMobile(), TypingDNA.version, TypingDNA.flags, diagramType, strLength, returnTextId, TypingDNA.history.getSpecialKeys()]);
935934
if (str != undefined && str.length > 0 && typeof str === 'string') {
935+
var strLower = str.toLowerCase();
936+
var strUpper = str.toUpperCase();
936937
var lastFoundPos = [];
937938
var lastPos = 0;
939+
var strUpperCharCode;
940+
var currentSensitiveCharCode;
938941
for (var i = 0; i < str.length; i++) {
939942
var currentCharCode = str.charCodeAt(i);
943+
if (!caseSensitive) {
944+
strUpperCharCode = strUpper.charCodeAt(i);
945+
currentSensitiveCharCode = (strUpperCharCode != currentCharCode) ? strUpperCharCode : strLower.charCodeAt(i);
946+
}
940947
var startPos = lastPos;
941948
var finishPos = diagramHistoryLength;
942-
var found = false
943-
while (found == false){
949+
var found = false;
950+
while (found == false) {
944951
for (var j = startPos; j < finishPos; j++) {
945952
var arr = stackDiagram[j];
946953
var charCode = arr[3];
947-
if (charCode == currentCharCode) {
954+
if (charCode == currentCharCode || (!caseSensitive && charCode == currentSensitiveCharCode)) {
948955
found = true;
949956
if (j == lastPos) {
950957
lastPos++;

0 commit comments

Comments
 (0)