This is NOT a supported way to extend CRXDE Lite, infact afaik there is no supported/documented way to extend CRXDE Lite. If you always truly :) follow best practices in a project, STOP here, do not read further
Goal
Create a
Password Type in
CRXDE Lite for users to enter passwords (mask characters while typing password type attribute values). Password type values can be stored in plain text or
Encrypted on file system. Please comment if you find bugs and a possible fix...
For a supported way to hide passwords (or other attributes)
check this postDemo |
Package InstallPassword Type in CRXDE LiteSample password stored as plain text (eg. author\crx-quickstart\launchpad\config\com\experienceaem\crxde\lite)
service.pid="com.experienceaem.crxde.lite.ExtensionConfig"
testMulti=["hi","there"]
testPassword="Password:
password_changed"
testString="hithere"
testLong=L"1"
service.pid="com.experienceaem.crxde.lite.ExtensionConfig"
testMulti=["hi","there"]
testPassword="Password:{d498726918ffd35347bd536b4421915082c97e26074b499d136084ab905ded2c}"
testString="hithere"
testLong=L"1"
Solution
Follow the two steps below to extend CRXDE Lite and add necessary JS code to create Password type. First step is
Not Upgrade-Proof, so when you upgrade CQ, the first step may have to be performed again
Step 1 - Update CRXDE Lite JarAll we do in this step is copy (back it up just in case if something goes wrong) the serialized CRXDE lite jar, open it and add a small chunk of JS code in it so that any extensions we code are loaded by the added JS logic when lite is opened in browser. The following steps are also
shown in demo1) Access bundles console
http://localhost:4502/system/console/bundles and find the
CRXDE Support bundle
2) Search for the serialized bundle on filesystem and copy it to a temp location (take a backup before you modify). On my AEM 6 SP1 its available in
author\crx-quickstart\launchpad\installer (rsrc-
com.adobe.granite.crxde-lite-1.0.66-CQ600-B0001.jar-1415034571045.ser)
3) Rename the copied
.ser file to
.jar (eg. rsrc-com.adobe.granite.crxde-lite-1.0.66-CQ600-B0001.jar-1415034571045
.ser -> rsrc-com.adobe.granite.crxde-lite-1.0.66-CQ600-B0001
.jar)
4) Open the jar using zip executable (say winrar), open file
docroot\js\start.js in any text editor and add following code at the end. Save file and a winrar confirmation should popup asking if the jar should be updated with saved file.
Ext.onReady(function() {
var loadLiteExtns = function(){
Ext.Ajax.request({
url: "/apps/ext-crx-delite/files.txt",
success: function(response, options) {
var js = response.responseText;
if(!js){
return;
}
js = js.split("\n");
Ext.each(js, function(jsPath) {
Ext.Ajax.request({
url: jsPath,
success: function(response, options) {
eval(response.responseText);
}
});
});
}
});
};
CRX.util.Util.on("reinit", function(){
location.reload();
});
loadLiteExtns();
});
5) In the above steps we add necessary code to load the extension files entered in
/apps/ext-crx-delite/files.txt. So whenever a new CRXDE Lite extension is needed a new line with extension file path can be added in
/apps/ext-crx-delite/files.txt6) Access
http://localhost:4502/system/console/bundles, click
Install/Update... to upload and update CQ with the new CRXDE Support jar having necessary code to load the CRXDE Lite extension files.
Step 2 - Add extension files in CRXIn this step we add the JS file containing logic to create a
Password type (like
String type)
1) Access http://localhost:4502/crx/de
2) Create node
/apps/ext-crx-delite of type nt:folder
3) Create node
/apps/ext-crx-delite/files.txt of type nt:file and add the following line. The logic added in
Step 1 reads this file for loading JS extension files added as paths
/apps/ext-crx-delite/hide-password.js
4) Create node
/apps/ext-crx-delite/hide-password.js of type nt:file and add the following code
Ext.ns("ExperienceAEM");
ExperienceAEM.PASSWORD = "Password";
ExperienceAEM.PropertyPanel = Ext.extend(CRX.ide.PropertyPanel,{
MASK: "****",
constructor: function(config){
ExperienceAEM.PropertyPanel.superclass.constructor.call(this, config);
var eThis = this;
this.types.store.loadData([ExperienceAEM.PASSWORD],true);
var valueColumn = this.getColumnModel().getColumnById("value");
valueColumn.renderer = function(value, p, record) {
var rValue = Ext.grid.Column.prototype.renderer.call(this, value, p, record);
if( (typeof rValue) != "string"){
return rValue;
}
var indexOfPassword = rValue.indexOf(ExperienceAEM.PASSWORD + ":");
if( indexOfPassword == 0){
record.data.type = ExperienceAEM.PASSWORD;
}
return (record.data.type == ExperienceAEM.PASSWORD) ? eThis.MASK : rValue;
};
},
initValue: function() {
ExperienceAEM.PropertyPanel.superclass.initValue.call(this);
this.value[ExperienceAEM.PASSWORD] = {
xtype: "textfield",
inputType: "password",
allowBlank: true,
disableKeyFilter: true,
cls: "x-form-text",
tabIndex: 102
};
}
});
Ext.reg("propertypanel", ExperienceAEM.PropertyPanel);
(function(){
var handler = CRX.ide.SaveAllAction.initialConfig.handler;
CRX.ide.SaveAllAction.initialConfig.handler = function(){
var workspaces = CRX.Util.getWorkspaces();
var dirtyPassRecs = [];
workspaces.each(function(workspace) {
var paths = CRX.State.getChangedPaths("/" + workspace + "/");
if (paths.length == 0) {
return;
}
Ext.each(paths, function(path){
var records = CRX.State.getPropertyRecords(path);
Ext.each(records, function(record) {
if ( (record.data.type !== ExperienceAEM.PASSWORD) || !record.dirty){
return;
}
record.data.type = CRX.util.STRING;
//comment the below line if you use encryption
record.data.value = ExperienceAEM.PASSWORD + ":" + record.data.value;
dirtyPassRecs.push(record);
});
});
});
var words = [];
Ext.each(dirtyPassRecs, function(record) {
words.push(record.data.value);
});
/*
uncomment this block to use encryption
//http://experience-aem.blogspot.com/2014/11/aem-6-sp1-servlet-for-encryption-decryption.html
Ext.Ajax.request({
url: "/bin/experienceaem/encrypt?words=" + words.join(","),
success: function(response) {
var words = JSON.parse(response.responseText);
Ext.each(dirtyPassRecs, function(record) {
record.data.value = ExperienceAEM.PASSWORD + ":" + words[record.data.value];
});
handler();
Ext.each(dirtyPassRecs, function(record) {
record.data.type = ExperienceAEM.PASSWORD;
});
}
});*/
//start: comment the below lines to use encryption
handler();
Ext.each(dirtyPassRecs, function(record) {
record.data.type = ExperienceAEM.PASSWORD;
});
//end:
}
})();
5) Make sure logic strips off the leading
Password: string when reading a stored password, from CRX, to get the actual password (further if password is encrypted, make sure you decrypt it before using...)