Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Jul 26, 2016
1 parent a40f0f5 commit b8c7e68
Show file tree
Hide file tree
Showing 7 changed files with 366 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ trait DirectiveField extends BaseField with SectionChildField {
//update list error accordingly
def parseClient(s: String): Unit


//reference to other fields used by that field
protected var _usedFields = Seq[DirectiveField]()
def usedFields_=(fields: Seq[DirectiveField]): Unit = {
Expand Down Expand Up @@ -166,7 +165,6 @@ trait DirectiveField extends BaseField with SectionChildField {

override def displayHtml = Text(toClient)


def tooltipElem = {
if (tooltip == "") {
NodeSeq.Empty
Expand All @@ -180,7 +178,7 @@ trait DirectiveField extends BaseField with SectionChildField {
def display(value: NodeSeq) = {
<tr>
<td class="directiveVarLabel">
{ displayName + { if (optional) " (optional)" else "" } }: {tooltipElem}
<span>{ if (optional) displayName else <b>{ displayName}</b> } {tooltipElem} {if (optional) <span class="tw-bs"> - <small style="color:#999;">Optional</small></span>}</span>
</td>
<td class="directiveVarValue">{ value }</td>
</tr>
Expand Down Expand Up @@ -213,7 +211,6 @@ trait DirectiveField extends BaseField with SectionChildField {
}
}


object DirectiveField {
val logger = LoggerFactory.getLogger(classOf[DirectiveField])
}
Expand Down Expand Up @@ -559,7 +556,6 @@ case class DirectiveEditor(
, val providesExpectedReports: Boolean
) extends HashcodeCaching {


// We do not remove duplicate in case of meta-technique
def removeDuplicateSections : Unit = providesExpectedReports match {
case true => Unit
Expand Down Expand Up @@ -606,5 +602,3 @@ case class DirectiveEditor(
</div>
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ import org.joda.time.format.DateTimeFormatter
import net.liftweb.util.FieldError
import com.normation.cfclerk.domain._
import net.liftweb.http.SHtml.ChoiceHolder
import com.normation.cfclerk.domain.HashAlgoConstraint.PLAIN
import com.normation.cfclerk.domain.HashAlgoConstraint.PreHashed
import net.liftweb.util.CssSel
import net.liftweb.util.Helpers

/**
* This field is a simple input text, without any
Expand Down Expand Up @@ -108,7 +112,6 @@ class ReadOnlyTextField(val id:String) extends DirectiveField {
def getDefaultValue = ""
}


/**
* A textarea field, with a css class
* "textareaField"
Expand Down Expand Up @@ -591,21 +594,22 @@ class PasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoConstra
else chosenAlgo.serialize(newInput.getBytes())
}


def parseClient(s: String): Unit = {
if (null == s) _x = "" else _x = s
}
def toClient: String = if (null == _x) "" else _x

def get = _x
def get = {
_x
}

//initialize the field
def set(x: String) = {
if (null == x || "" == x) _x = ""
else {
_x = x
val r = {
HashAlgoConstraint.unserializeIn(algos.toSet, x) match {
HashAlgoConstraint.unserialize( x) match {
case Full((a,hash)) =>
//update the hash algo to use only if not specified.
//we don't check if previous hash and current algo matches: we only enforce
Expand Down Expand Up @@ -634,7 +638,7 @@ class PasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoConstra
def toForm = {
//the radio - the default value is keep
val (radioKeep, radioChange, radioBlank) = {
val radios : ChoiceHolder[String] = SHtml.radio(Seq("keep","change", "blank"), Full(currentRadio), { s =>
val radios : ChoiceHolder[String] = SHtml.radio(Seq("keep","change", "blank", "pre-hashed", "clear"), Full(currentRadio), { s =>
currentRadio = s
s match {
case "keep" => blank = false ; keepCurrent = true;
Expand All @@ -651,7 +655,7 @@ class PasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoConstra
"name=hash" #> (if(algos.size == 1) {
Text(algos.head.prefix.toUpperCase)
} else {
SHtml.selectObj(algos.map(a => (a, a.prefix.toUpperCase))
SHtml.selectObj(algos.filterNot { x => x == PLAIN || x == PreHashed}.map(a => (a, a.prefix.toUpperCase))
, Box(currentAlgo)
, { (a:HashAlgoConstraint) => currentAlgo = Some(a) }
)
Expand All @@ -674,13 +678,30 @@ class PasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoConstra
})
}


Full(form.apply(PasswordField.xml))

}
}

object PasswordField {

def xmlV2(id : String) = {
// Html template
def templatePath = List("templates-hidden", "components", "passwordInput")
def template() = Templates(templatePath) match {
case Empty | Failure(_,_,_) =>
sys.error(s"Template for password input configuration not found. I was looking for ${templatePath.mkString("/")}.html")
case Full(n) => n
}
def agentScheduleTemplate = chooseTemplate("password", "input", template)

val css: CssSel = ".tw-bs [id]" #> id &
".password-section [id]" #> (id+"-controller")

css(agentScheduleTemplate)

}

val xml =
<table>
<tr><td colspan="2"><div zone="currentValue">Current password<span zone="value">(SHA256 hash): ce94806f8020be351fe3e492808a23a5b929c28a</span></div></td></tr>
Expand Down Expand Up @@ -734,11 +755,10 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC

//the algo to use
private[this] var currentAlgo: Option[HashAlgoConstraint] = algos.headOption
private[this] var currentHash: String = ""

private[this] var currentHash: Option[String] = None
//to store the result
private[this] var currentValue: String = ""
private[this] var currentRadio: String = "keep"
private[this] var currentValue: Option[String] = None
private[this] var currentRadio: String = "keep"

private[this] var blank = false
private[this] var keepCurrent = true
Expand All @@ -754,29 +774,42 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC
s.updateValue(keepCurrentPwd, blankPwd, pastValue, newInput, chosenAlgo)
}

currentValue = newInput
currentValue = Some(newInput)

if(keepCurrentPwd) pastValue
else if(blankPwd) ""
else if(newInput == "") ""
else chosenAlgo.serialize(newInput.getBytes())
}

def parseClient(s: String) = {
import net.liftweb.json._
val json = parse(s)
logger.info(json)
for {
JField("password" , JString(password)) <- json
JField("hash" , JString(hash)) <- json
algo = HashAlgoConstraint.fromString(hash).getOrElse(PLAIN)
} yield {
_x = newInternalValue(false,false,toClient, password, algo)
}

def parseClient(s: String): Unit = {
if (null == s) _x = "" else _x = s
//if (null == s) _x = "" else _x = s
}
def toClient: String = if (null == _x) "" else _x

def get = _x
def get = {

_x
}

//initialize the field
def set(x: String) = {
if (null == x || "" == x) _x = ""
else {
_x = x
val r = {
HashAlgoConstraint.unserializeIn(algos.toSet, x) match {
HashAlgoConstraint.unserialize( x) match {
case Full((a,hash)) =>
//update the hash algo to use only if not specified.
//we don't check if previous hash and current algo matches: we only enforce
Expand All @@ -790,7 +823,7 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC
}
}
currentAlgo = r._1
currentHash = r._2
currentHash = Some(r._2)
}

//initialise what to display for "current value" the first time
Expand All @@ -808,7 +841,6 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC

val hashList = toClient :: slaves.collect { case s if(s.toClient != "") => s.toClient }


(
<span> ({algoName} hash):</span>
<ul style="overflow-x: scrollbar">{hashList.map(x => <li><pre>{x.replaceAll(":", ": ").take(60)}...</pre></li>)}</ul>
Expand All @@ -823,14 +855,16 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC

def name = a match {
case PLAIN => "Verbatim text"
case PreHashed => "Pre hashed"
case SCRIPT => "Script"
case MD5 => "MD5 (Non salted)"
case SHA1 => "SHA1 (Non salted)"
case SHA256 => "SHA256 (Non salted)"
case SHA512 => "SHA512 (Non salted)"
case LinuxShadowMD5 | AixMD5 => "MD5 (Unix Crypt)"
case LinuxShadowSHA256 | AixSHA256 => "SHA256 (Unix Crypt)"
case LinuxShadowSHA512 | AixSHA512 => "SHA512 (Unix Crypt)"
case UnixCryptDES => "DES (Unix Crypt)"
case LinuxShadowMD5 | AixMD5 => "MD5"
case LinuxShadowSHA256 | AixSHA256 => "SHA256"
case LinuxShadowSHA512 | AixSHA512 => "SHA512"
case UnixCryptDES => "DES"
}
}

Expand All @@ -848,43 +882,23 @@ class MasterPasswordField(val id: String, blankable:Boolean, algos:Seq[HashAlgoC
(radios(0),radios(1),radios(2))
}

val form =
"zone=value *" #> currentValue() &
"zonechooseHash" #> ( (xml:NodeSeq) => if(algos.size < 1) Text(s"hash with) ${algos.head.prefix.toUpperCase}") else xml ) &
"name=hash" #> (if(algos.size == 1) {
Text(algos.head.prefix.toUpperCase)
} else {
SHtml.selectObj(algos.map(a => (a, a.name))
, Box(currentAlgo)
, { (a:HashAlgoConstraint) => currentAlgo = Some(a) }
)
} ) &
".radioKeep" #> radioKeep &
".radioChange" #> radioChange &
"name=password" #> S.formGroup(10) { //use formGroup because must be the last evaluated method
//always "" for default value
SHtml.password(
currentValue
// ".get" should be licit at that point, because is only when reading from LDAP
, {s => parseClient(newInternalValue(keepCurrent, blank, toClient, s, currentAlgo.get)) }
)
} &
"zone=blank" #> { (nodes:NodeSeq) =>
(if(blankable) {
(".radioBlank" #> { (nodes:NodeSeq) => radioBlank }).apply(nodes)
} else {
NodeSeq.Empty
})
}


Full(form.apply(PasswordField.xml))
val hashes = JsObj(algos.filterNot { x => x == PLAIN || x == PreHashed }.map(a => (a.prefix, Str(a.name))):_*)
val formId = Helpers.nextFuncName
val valueInput = SHtml.text("", s => parseClient(s), ("ng-model","result"), ("ng-hide", "true") )
val initScript = {
Script(OnLoad( JsRaw(s"""
angular.bootstrap("#${formId}", ['password']);
var scope = angular.element($$("#${formId}-controller")).scope();
scope.$$apply(function(){
scope.init(${currentHash.map(Str(_).toJsCmd).getOrElse("undefined")}, ${currentAlgo.map(x =>Str(x.prefix).toJsCmd).getOrElse("undefined")}, ${hashes.toJsCmd});
} );""")))
}
val form2 = (".password-section *+" #> valueInput).apply(PasswordField.xmlV2(formId)) ++ initScript
Full(form2)

}
}



class DerivedPasswordField(val id: String, mapping: HashAlgoConstraint.DerivedPasswordType) extends DirectiveField {
self =>
type ValueType = String
Expand All @@ -897,13 +911,11 @@ class DerivedPasswordField(val id: String, mapping: HashAlgoConstraint.DerivedPa
def validations = Nil
def setFilter = Nil


//the actual backend value like: sha1:XXXXXX
private[this] var _x: String = getDefaultValue

//the mapping between source algo and corresponding algo


/*
* Update internal value thanks to a new value from the
* master passwords field
Expand All @@ -919,7 +931,6 @@ class DerivedPasswordField(val id: String, mapping: HashAlgoConstraint.DerivedPa
_x
}


def parseClient(s: String): Unit = {
if (null == s) _x = "" else _x = s
}
Expand Down
Loading

0 comments on commit b8c7e68

Please sign in to comment.