Skip to content

Commit

Permalink
Merge pull request #12 from ansibleguy76/release/v2.1.6
Browse files Browse the repository at this point in the history
v2.1.6 into main
  • Loading branch information
ansibleguy76 authored Jan 21, 2022
2 parents 3ff8650 + bb8d3f7 commit 27531c5
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 61 deletions.
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.1.6] - 2022-01-21

### Changed

- Secured JWT tokens even more

### Fixed

- Fixed editable expression bug
- Token issue

## [2.1.5] - 2022-01-20

### Added

- Start with changelog
- Start with version releases

## [2.1.4] - 2022-01-20
=======
## [2.1.5] - 2022-01-20

## [2.1.4] - 2022-01-20
Expand All @@ -20,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Hide AWX token
- Add AWX ca-bundle for certificate verification
- JWT tokens, allow multiple devices
- Expression field can be `editable`


## [2.1.2] - 2022-01-17

Expand Down Expand Up @@ -85,6 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow change password for current local user
- Start tracking versions

[Unreleased]: https://github.com/ansibleguy76/ansibleforms/compare/2.1.5...HEAD
[Unreleased]: https://github.com/ansibleguy76/ansibleforms/compare/2.1.6...HEAD

[2.1.6]: https://github.com/ansibleguy76/ansibleforms/compare/2.1.5...2.1.6
[2.1.5]: https://github.com/ansibleguy76/ansibleforms/compare/2.1.4...2.1.5
4 changes: 2 additions & 2 deletions app_versions.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ext.version_code = 020105
ext.version_name = "2.1.5"
ext.version_code = 020106
ext.version_name = "2.1.6"
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ansible_forms_vue",
"version": "2.1.4",
"version": "2.1.6",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
106 changes: 72 additions & 34 deletions client/src/components/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,17 @@
<BulmaEditTable v-if="field.type=='table'" :tableFields="field.tableFields" :click="false" tableClass="table is-striped is-bordered is-narrow" v-model="$v.form[field.name].$model" />
<div :class="{'has-icons-left':!!field.icon && field.type!='query'}" class="control">
<!-- type = expression -->
<div v-if="field.type=='expression'" :class="{'is-loading':dynamicFieldStatus[field.name]==undefined || dynamicFieldStatus[field.name]=='running'}" class="control">
<div v-if="field.type=='expression'" :class="{'is-loading':(dynamicFieldStatus[field.name]==undefined || dynamicFieldStatus[field.name]=='running') &! fieldOptions[field.name].editable}" class="control">
<input type="text"
@focus="inputFocus"
:class="{'is-danger':$v.form[field.name].$invalid,'has-text-info':!fieldOptions[field.name].editable}"
v-model="$v.form[field.name].$model"
class="input"
:readonly="!fieldOptions[field.name].editable"
:name="field.name"
:required="field.required">
:required="field.required"
@change="evaluateDynamicFields(field.name)"
>
</div>
<!-- type = text or password-->
<input v-if="field.type=='text' || field.type=='password'"
Expand Down Expand Up @@ -353,14 +355,15 @@
e.preventDefault();
},
setExpressionFieldEditable(fieldname,value){
if(typeof this.$v.form[fieldname].$model=='string' || this.$v.form[fieldname].$model==undefined){
if(typeof this.$v.form[fieldname].$model=='string' || typeof this.$v.form[fieldname].$model=='number' || this.$v.form[fieldname].$model==undefined){
Vue.set(this.fieldOptions[fieldname],'editable',value) // flag editable
}else{
this.$toast.warning("You can only edit string expression fields.")
}
if(!value){
Vue.set(this.dynamicFieldStatus,fieldname,undefined); // reset statusflag
Vue.set(this.form,fieldname,undefined); // reset value in the form
this.resetField(fieldname)
// Vue.set(this.dynamicFieldStatus,fieldname,undefined); // reset statusflag
// Vue.set(this.form,fieldname,undefined); // reset value in the form
}
},
filterfieldsByGroup(group){ // creates a list of field per group
Expand Down Expand Up @@ -404,15 +407,31 @@
});
return result
},
resetField(field){
resetField(fieldname){
// reset to default value
// reset this field status
if(field in this.dynamicFieldStatus){
this.dynamicFieldStatus[field]=undefined
// console.log(`[${fieldname}] reset`)
if(fieldname in this.dynamicFieldStatus){
this.dynamicFieldStatus[fieldname]=undefined
}
Vue.set(this.form,fieldname,this.defaults[fieldname])
this.evaluateDynamicFields(fieldname)
},
defaultField(fieldname){
// reset to default value
// reset this field status
// console.log(`[${fieldname}] default`)
var prevState=this.dynamicFieldStatus[fieldname]
if(fieldname in this.dynamicFieldStatus && this.defaults[fieldname]){
this.dynamicFieldStatus[fieldname]="default"
}else{
this.dynamicFieldStatus[fieldname]=undefined
}
Vue.set(this.form,fieldname,this.defaults[fieldname])
// don't evaluate again, the default didn't change
if(prevState!="default"){
this.evaluateDynamicFields(fieldname)
}
Vue.set(this.form,field,this.defaults[field])
this.evaluateDynamicFields(field)
},
// Find variable devDependencies
findVariableDependencies(){
Expand Down Expand Up @@ -536,35 +555,44 @@
}
// if the variable is viable and not being changed, replace it
//console.log(foundfield + "("+fieldvalue+")" + " -> targetflag = " + targetflag)
// console.log(foundfield + "("+fieldvalue+")" + " -> targetflag = " + targetflag)
// console.log(foundfield + " -> targetflag = " + targetflag)
if((((targetflag=="variable")||(targetflag=="fixed")) && fieldvalue!==undefined && newValue!=undefined)||((item.ignoreIncomplete||false) && newValue!=undefined)){ // valid value ?
if(((targetflag=="variable"||targetflag=="fixed"||targetflag=="default") && fieldvalue!==undefined && newValue!=undefined)||((item.ignoreIncomplete||false) && newValue!=undefined)){ // valid value ?
if(fieldvalue==undefined){
fieldvalue="__undefined__" // catch undefined values
}
if(typeof fieldvalue==='object' || Array.isArray(fieldvalue)){
fieldvalue = JSON.stringify(fieldvalue) // if object, we need to stringify it
}
// console.log("replacing placeholder")
fieldvalue=ref.stringifyValue(fieldvalue)
// console.log("replacing placeholder")
newValue=newValue.replace(foundmatch,fieldvalue); // replace the placeholder with the value
// console.log("replaced")
// console.log(item.name + " -> " + newValue)
// console.log("replaced")
// console.log(item.name + " -> " + newValue)
}else{
newValue=undefined // cannot evaluate yet
// we have a placeholder but it's value is not ready yet... will be for next loop
// console.log("dependency ("+foundfield+") is not ready (" + targetflag + " : " + fieldvalue + ")")
// if(item.alwaysEval){
// newValue=newValue.replace(foundmatch,"undefined"); // replace the placeholder with undefined
// }else{
newValue=ref.stringifyValue(item.default) // cannot evaluate yet
// we have a placeholder but it's value is not ready yet... will be for next loop
// console.log("dependency ("+foundfield+") is not ready (" + targetflag + " : " + fieldvalue + ")")
// }
}
hasPlaceholders=true;
}
if(retestRegex.test(newValue)){ // still placeholders found ?
newValue=undefined // cannot evaluate yet
newValue=ref.stringifyValue(item.default) // cannot evaluate yet
}
if(newValue!=undefined){
newValue=newValue.replace("'__undefined__'","undefined") // replace undefined values
newValue=newValue.replace("__undefined__","undefined")
}
return {"hasPlaceholders":hasPlaceholders,"value":newValue} // return the result
},
stringifyValue(fieldvalue){
if(typeof fieldvalue==='object' || Array.isArray(fieldvalue)){
return JSON.stringify(fieldvalue) // if object, we need to stringify it
}else{
return fieldvalue
}
},
//----------------------------------------------------------------
// starts the evaluation of dynamic fields (expression or query)
//----------------------------------------------------------------
Expand All @@ -589,15 +617,18 @@
// if expression and not processed yet or needs to be reprocessed
var flag = ref.dynamicFieldStatus[item.name]; // current field status (running/fixed/variable)
var placeholderCheck=undefined; // result for a placeholder check
if(((item.type=="expression" && item.expression) || (item.type=="query" && item.expression)) && flag==undefined){ // if expression and not evaluated yet
if(((item.type=="expression" && item.expression) || (item.type=="query" && item.expression)) && (flag==undefined || flag=="default")){ // if expression and not evaluated yet
// console.log("eval expression " + item.name)
// console.log(`[${item.name}][${flag}] : ok !! let do it`)
if(item.required){
hasUnevaluatedFields=true // set the un-eval flag if this is required
}
// set flag running
Vue.set(ref.dynamicFieldStatus,item.name,"running"); // set as running
placeholderCheck = ref.replacePlaceholders(item) // check and replace placeholders
// console.log(`[${item.name}] 1 : ${placeholderCheck.value}`)
if(placeholderCheck.value!=undefined){ // expression is clean ?
// console.log(`[${item.name}] 2 : ${placeholderCheck.value}`)
// allow local run in browser
if(item.runLocal){
//console.log("Running local expression : " + placeholderCheck.value)
Expand All @@ -612,14 +643,16 @@
// set flag as viable variable query
// console.log("Expression found with variables")
Vue.set(ref.dynamicFieldStatus,item.name,"variable");
//
}else{
// set flag as viable fixed query
Vue.set(ref.dynamicFieldStatus,item.name,"fixed"); // if this dynamic field was a 1 time evaluation, set as fixed
}
}catch(err){
//console.log("Local eval failed : " + err)
try{
Vue.set(ref.dynamicFieldStatus,item.name,undefined);
ref.defaultField(item.name)
}catch(err){
ref.stopLoop()
}
Expand All @@ -641,18 +674,21 @@
Vue.set(ref.queryresults, item.name, [].concat(restresult.data.output??[]));
if(placeholderCheck.hasPlaceholders){ // if placeholders were found we set this a variable dynamic field.
// set flag as viable variable query
// console.log("Expression found with variables")
// console.log(`[${item.name}] : variable`)
Vue.set(ref.dynamicFieldStatus,item.name,"variable");
}else{
// set flag as viable fixed query
Vue.set(ref.dynamicFieldStatus,item.name,"fixed"); // if this dynamic field was a 1 time evaluation, set as fixed
}
// console.log(item.name + " is now resolved ("+restresult.data.output+"), let's cascade")
//ref.evaluateDynamicFields(item.name)
}
}).catch(function (error) {
// console.log('Error ' + error.message)
try{
Vue.set(ref.dynamicFieldStatus,item.name,undefined);
ref.defaultField(item.name)
}catch(err){
ref.stopLoop()
}
Expand All @@ -663,7 +699,7 @@
}else{
// console.log(item.name + " is not evaluated yet");
Vue.set(ref.dynamicFieldStatus,item.name,undefined);
ref.defaultField(item.name)
}
} else if(((item.type=="query" && item.query) || (item.type=="expression" && item.query)) && flag==undefined){
// console.log("eval query : " + item.name)
Expand Down Expand Up @@ -704,7 +740,7 @@
}).catch(function (err) {
// console.log('Error ' + err.message)
try{
Vue.set(ref.dynamicFieldStatus,item.name,undefined);
ref.defaultField(item.name)
}catch(err){
ref.$toast("Cannot reset field status " + item.name)
}
Expand All @@ -722,9 +758,10 @@
}
}
}else{ // not visible field
ref.resetField(item.name)
ref.defaultField(item.name)
}
} // end loop function
) // end field loop
if(hasUnevaluatedFields){
Expand Down Expand Up @@ -779,13 +816,14 @@
}
};
},
evaluateDynamicFields(field) {
evaluateDynamicFields(fieldname) {
var ref=this;
// console.log('evaldynfields triggered for ' + fieldname)
// if this field is dependency
if(field in ref.dynamicFieldDependencies){ // are any fields dependent from this field ?
if(fieldname in ref.dynamicFieldDependencies){ // are any fields dependent from this field ?
ref.canSubmit=false; // after each dependency reset, we block submitting, untill all fields are resolved
// set all variable ones to dirty
ref.dynamicFieldDependencies[field].forEach((item,i) => { // loop all dynamic fields and reset them
ref.dynamicFieldDependencies[fieldname].forEach((item,i) => { // loop all dynamic fields and reset them
// set all variable fields blank and re-evaluate
if(!ref.fieldOptions[item].editable){
Vue.set(ref.dynamicFieldStatus,item,undefined); // reset statusflag
Expand Down Expand Up @@ -1113,7 +1151,7 @@
Vue.set(ref.fieldOptions[item.name],"valueColumn",item.valueColumn||"")
Vue.set(ref.fieldOptions[item.name],"placeholderColumn",item.placeholderColumn||"")
Vue.set(ref.fieldOptions[item.name],"type",item.type)
Vue.set(ref.form,item.name,undefined)
Vue.set(ref.form,item.name,item.default)
}else if(["checkbox"].includes(item.type)){
Vue.set(ref.form,item.name,item.default||false)
}else{
Expand Down
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ansible_forms",
"version": "2.1.4",
"version": "2.1.6",
"repository": {
"type": "git",
"url": "git://github.com/ansibleguy76/ansibleforms.git"
Expand Down
8 changes: 6 additions & 2 deletions server/src/auth/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,14 @@ passport.use(
},
async (jwtPayload, done) => {
try {
return done(null, jwtPayload);
if(jwtPayload.access){
return done(null, jwtPayload);
}else {
done(null, false,{message:'Bad accesstoken'})
}
} catch (error) {
logger.debug("error ?")
done(error);
done(error,false,{message:'Unknown JWT error'});
}
}
)
Expand Down
4 changes: 2 additions & 2 deletions server/src/controllers/login.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ exports.login = async function(req, res,next) {
// {"username":"administrator","type":"local","roles":["public","admin"]}

// we create 2 jwt tokens (accesstoken and refresh token)
const token = jwt.sign({user}, authConfig.secret,{ expiresIn: authConfig.jwtExpiration});
const refreshtoken = jwt.sign({user}, authConfig.secret,{ expiresIn: authConfig.jwtRefreshExpiration});
const token = jwt.sign({user,access:true}, authConfig.secret,{ expiresIn: authConfig.jwtExpiration});
const refreshtoken = jwt.sign({user,refresh:true}, authConfig.secret,{ expiresIn: authConfig.jwtRefreshExpiration});

// we store the tokens in the database, to later verify a refresh token action
logger.debug("Storing refreshtoken in database for user " + user.username)
Expand Down
6 changes: 3 additions & 3 deletions server/src/controllers/token.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ exports.refresh = function(req, res) {
res.status(400).send({ error:true, message: 'Please provide a refresh token' });
}else{
var jwtPayload=jwt.decode(refreshtoken)
if(jwtPayload && jwtPayload.user){
if(jwtPayload && jwtPayload.user && jwtPayload.refresh){
var username=jwtPayload.user.username
var username_type=jwtPayload.user.type
User.checkToken(username,username_type,refreshtoken,function(err,result){
Expand All @@ -27,8 +27,8 @@ exports.refresh = function(req, res) {
var body = jwtPayload.user
if(new Date(jwtPayload.exp*1000)>new Date()){
// logger.debug("refresh token is not expired")
const token = jwt.sign({ user: body }, authConfig.secret,{ expiresIn: authConfig.jwtExpiration});
const refreshtoken = jwt.sign({ user: body }, authConfig.secret,{ expiresIn: authConfig.jwtRefreshExpiration});
const token = jwt.sign({ user: body,access:true }, authConfig.secret,{ expiresIn: authConfig.jwtExpiration});
const refreshtoken = jwt.sign({ user: body,refresh:true }, authConfig.secret,{ expiresIn: authConfig.jwtRefreshExpiration});
User.storeToken(username,username_type,refreshtoken,function(err,resnewtoken){
if(err){
logger.error("Failed to store new token")
Expand Down
Loading

0 comments on commit 27531c5

Please sign in to comment.