branch feature/pollen-riot-js updated (57673fc -> c9359ff)
This is an automated email from the git hooks/post-receive script. New change to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git from 57673fc debut formulaire de création de sondage (le squelette) + améliorations sur les écrans de connexion new 8ee9e61 ajout des choix de type text + quelques améliorations ailleurs new 99f2665 Use same configuration as default bundle application for dev new b0e0ac1 Amélioration i18n + utilisation base par défaut sinon certaines pages ne sont pas accessibles en direct new c9359ff Review security and use now cookies to store authentication informations The 4 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit c9359ffbd941d89d4e719953a9955a360be96c1d Author: Tony CHEMIT <dev@tchemit.fr> Date: Sun Jan 15 13:41:37 2017 +0100 Review security and use now cookies to store authentication informations commit b0e0ac1cca44ba5c2f8704e618d1b1ad425b1db9 Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 14:41:39 2017 +0100 Amélioration i18n + utilisation base par défaut sinon certaines pages ne sont pas accessibles en direct commit 99f26655168eadd0894cd76bbfe4dcd40aeb621a Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 08:39:27 2017 +0100 Use same configuration as default bundle application for dev commit 8ee9e61a60000dc64c20232849e7f531efa9ab96 Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 08:04:41 2017 +0100 ajout des choix de type text + quelques améliorations ailleurs Summary of changes: pollen-rest-api/pom.xml | 25 +-- .../rest/api/PollenRestApiRequestFilter.java | 85 ++++++++- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 52 +++++- pollen-rest-api/src/main/resources/mapping | 1 + pollen-rest-api/src/main/webapp/WEB-INF/web.xml | 35 +++- pollen-services/pom.xml | 5 + pollen-services/src/main/config/PollenServices.ini | 16 +- .../security/DefaultPollenSecurityContext.java | 1 + ...on.java => MissingAuthenticationException.java} | 2 +- .../security/PollenCypherTechnicalException.java | 16 ++ .../service/security/PollenSecurityContext.java | 2 + .../services/service/security/SecurityService.java | 202 ++++++++++++++++++--- .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + .../service/PollenUIUrlRenderServiceTest.java | 14 +- pollen-ui-riot-js/src/main/web/conf.json | 2 +- pollen-ui-riot-js/src/main/web/i18n.json | 186 ++++++++++--------- pollen-ui-riot-js/src/main/web/index.js | 8 +- pollen-ui-riot-js/src/main/web/js/AuthService.js | 59 ++---- pollen-ui-riot-js/src/main/web/js/ChoiceText.js | 9 + .../src/main/web/js/EmitterService.js | 16 +- pollen-ui-riot-js/src/main/web/js/FetchService.js | 3 - pollen-ui-riot-js/src/main/web/js/I18nHelper.js | 52 ++---- pollen-ui-riot-js/src/main/web/js/PollForm.js | 68 ++++--- pollen-ui-riot-js/src/main/web/js/Session.js | 36 +++- pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag | 18 +- .../src/main/web/tag/CreatePollHeader.tag | 5 +- pollen-ui-riot-js/src/main/web/tag/Footer.tag | 10 +- pollen-ui-riot-js/src/main/web/tag/Header.tag | 25 +-- pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag | 2 +- pollen-ui-riot-js/src/main/web/tag/Home.tag | 6 +- .../src/main/web/tag/PollChoiceText.tag | 39 ++++ .../src/main/web/tag/PollChoiceTextGroup.tag | 14 ++ .../src/main/web/tag/PollChoicesText.tag | 75 ++++++-- .../src/main/web/tag/PollDescription.tag | 48 +++-- pollen-ui-riot-js/src/main/web/tag/Pollen.tag | 7 +- pollen-ui-riot-js/src/main/web/tag/SignCheck.tag | 82 ++++++++- pollen-ui-riot-js/src/main/web/tag/SignIn.tag | 18 +- pollen-ui-riot-js/src/main/web/tag/SignUp.tag | 18 +- .../src/main/web/tag/popup/AccountCreated.tag | 10 +- .../src/main/web/tag/popup/NewPassword.tag | 10 +- .../src/main/web/tag/popup/ResendValidation.tag | 10 +- pom.xml | 13 +- 43 files changed, 919 insertions(+), 388 deletions(-) copy pollen-services/src/main/java/org/chorem/pollen/services/service/security/{PollenInvalidPasswordException.java => MissingAuthenticationException.java} (93%) create mode 100644 pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenCypherTechnicalException.java create mode 100644 pollen-ui-riot-js/src/main/web/js/ChoiceText.js create mode 100644 pollen-ui-riot-js/src/main/web/tag/PollChoiceText.tag create mode 100644 pollen-ui-riot-js/src/main/web/tag/PollChoiceTextGroup.tag -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 8ee9e61a60000dc64c20232849e7f531efa9ab96 Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 08:04:41 2017 +0100 ajout des choix de type text + quelques améliorations ailleurs --- pollen-ui-riot-js/src/main/web/js/AuthService.js | 48 ++------------ pollen-ui-riot-js/src/main/web/js/ChoiceText.js | 9 +++ .../src/main/web/js/EmitterService.js | 16 +++-- pollen-ui-riot-js/src/main/web/js/FetchService.js | 6 +- pollen-ui-riot-js/src/main/web/js/PollForm.js | 68 ++++++++++++++------ pollen-ui-riot-js/src/main/web/js/Session.js | 35 ++++++++++ pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag | 17 +++-- .../src/main/web/tag/CreatePollHeader.tag | 5 +- pollen-ui-riot-js/src/main/web/tag/Header.tag | 8 +-- .../src/main/web/tag/PollChoiceText.tag | 39 +++++++++++ .../src/main/web/tag/PollChoiceTextGroup.tag | 14 ++++ .../src/main/web/tag/PollChoicesText.tag | 75 ++++++++++++++++++---- .../src/main/web/tag/PollDescription.tag | 48 ++++++++++---- pollen-ui-riot-js/src/main/web/tag/SignIn.tag | 2 +- 14 files changed, 279 insertions(+), 111 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index de60586..0efdabb 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -5,32 +5,13 @@ let FetchService = require("./FetchService"); class AuthService extends FetchService { - constructor() { - super(); - emitter.onUnauthorize(() => { - this.userPromise = null; - }); - - } - signIn(login, password) { return this.form("/v1/login", {login: login, password: password}) - .then((result) => { - if (!result) { + .then((auth) => { + if (!auth) { return Promise.reject(false); } - - session.auth = result; - console.info(session.auth); - - this.getUser().then( - user => { - console.info(user); - emitter.emitConnected(user); - } - ); - - + session.signIn(auth, this); return true; }); } @@ -40,29 +21,12 @@ class AuthService extends FetchService { } signOut() { - delete session.auth; - this.userPromise = null; + session.signOut(); return this.get("/v1/logout"); } - isConnected() { - return !!session.auth; - // return document.cookie.indexOf("pollen-connected=true") !== -1; - } - - getUser() { - if (!this.userPromise) { - this.userPromise = this.get("/v1/users/" + session.auth.id) - .then((result) => { - if (!result) { - this.userPromise = null; - return Promise.reject(); - } - return result; - }); - } - - return this.userPromise; + userPromise(auth) { + return this.get("/v1/users/" + auth.id); } validateEmail(userId, token) { diff --git a/pollen-ui-riot-js/src/main/web/js/ChoiceText.js b/pollen-ui-riot-js/src/main/web/js/ChoiceText.js new file mode 100644 index 0000000..d0e64d7 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/js/ChoiceText.js @@ -0,0 +1,9 @@ +class ChoiceText { + + constructor(text, description) { + this.text = text; + this.description = description; + } +} + +module.exports = ChoiceText; diff --git a/pollen-ui-riot-js/src/main/web/js/EmitterService.js b/pollen-ui-riot-js/src/main/web/js/EmitterService.js index df185d1..490fe83 100644 --- a/pollen-ui-riot-js/src/main/web/js/EmitterService.js +++ b/pollen-ui-riot-js/src/main/web/js/EmitterService.js @@ -1,10 +1,12 @@ let singleton = require("./Singleton"); -let EventEmitter = require('events'); -class EmitterService extends EventEmitter { +class EmitterService { + constructor() { + riot.observable(this); + } emitUnauthorize() { - this.emit("unauthorized"); + this.trigger("unauthorized"); } onUnauthorize(fn) { @@ -12,7 +14,7 @@ class EmitterService extends EventEmitter { } emitConnected(user) { - this.emit("connected", user); + this.trigger("connected", user); } onConnected(fn) { @@ -20,7 +22,7 @@ class EmitterService extends EventEmitter { } emitDisconnected(user) { - this.emit("disconnected", user); + this.trigger("disconnected", user); } onDisconnected(fn) { @@ -28,7 +30,7 @@ class EmitterService extends EventEmitter { } emitError() { - this.emit("error"); + this.trigger("error"); } onError(fn) { @@ -36,7 +38,7 @@ class EmitterService extends EventEmitter { } emitLocaleChanged(locale) { - this.emit("localeChanged", locale); + this.trigger("localeChanged", locale); } onLocaleChanged(fn) { diff --git a/pollen-ui-riot-js/src/main/web/js/FetchService.js b/pollen-ui-riot-js/src/main/web/js/FetchService.js index 71c70fd..41d36e4 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -9,8 +9,12 @@ class FetchService { headers["Content-Type"] = "application/json"; } - if (session.auth) { + if (session.isConnected()) { + console.info("CONNNNNNECTED!!!") + headers["X-Pollen-Session-Token"] = session.auth.permission; + } else { + console.info("NONONONOONONONON CONNNNNNECTED!!!") } return fetch( session.configuration.endPoint + url, { diff --git a/pollen-ui-riot-js/src/main/web/js/PollForm.js b/pollen-ui-riot-js/src/main/web/js/PollForm.js index feafb5e..54121ae 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -1,21 +1,12 @@ let singleton = require("./Singleton"); -let session = require("./Session"); -let EventEmitter = require('events'); +let ChoiceText = require('./ChoiceText'); class PollForm { constructor() { - this.emitter = new EventEmitter(); + riot.observable(this); this.step = 0; - this.model = { - title: "", - description: "", - userName: "", - userEmail: "", - textChoices: [], - imageChoices: [], - dateChoices: [], - }; + this.model = null; } previousStep() { @@ -26,27 +17,62 @@ class PollForm { this._setStep(this.step + 1); } - _init(configuration, user) { + init(user) { console.info("init form"); - console.info(configuration); - console.info(user); + this.model = { + title: "Mon premier sondage", + description: "", + name: "Tony Chemit", + email: "user@pollen.org", + textChoices: [new ChoiceText("Mozart", "Requiem is so powerfull"), + new ChoiceText("Schubert", "Truit is so nice"), new ChoiceText("Malher", "So deep, so dark...")], + imageChoices: [], + dateChoices: [] + }; if (user) { - this.model.userEmail = user.email; + //FIXME On doit aussi remonter le nom de l'utilisateur + this.model.name = user.email; + this.model.email = user.email; } } onStepChanged(fn) { - this.emitter.on("stepChanged", fn); + this.on("stepChanged", fn); + } + + fromTextChoices(form) { + let choices = []; + + let map = {}; + let count = 0; + Array.prototype.forEach.call(form.elements, (e) => { + if (e.name && e.value) { + if (e.name.indexOf("choice") == 0) { + map[e.name] = e.value; + count++; + } + if (e.name.indexOf("description") == 0) { + map[e.name] = e.value; + } + } + }); + + for (let i = 0; i < count; i++) { + let text = map['choice' + i]; + let description = map['description' + i]; + choices.push(new ChoiceText(text, description)); + } + console.info("FromTextChoices"); + console.info(choices); + this.model.textChoices = choices; } _setStep(step) { + console.info("set step:: " + step); this.step = step; - this._emitStepChanged(step); + this.trigger("stepChanged", step); } - _emitStepChanged(step) { - this.emitter.emit("stepChanged", step); - } } module.exports = singleton(PollForm); diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 238e0c1..2959f13 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -1,4 +1,5 @@ let singleton = require("./Singleton"); +let emitter = require("./EmitterService"); class Session { @@ -9,6 +10,8 @@ class Session { this.locale = null; // pour contenir la configuration this.configuration = null; + // pour contenir l'utillisateur connecté + this.user = null; let lang = navigator.language || navigator.userLanguage; if (lang.indexOf('en') == 0) { @@ -16,6 +19,38 @@ class Session { } else { this.locale = 'fr'; } + emitter.onUnauthorize(() => { + this.user = null; + }); + } + + isConnected() { + return !!this.auth; + // return document.cookie.indexOf("pollen-connected=true") !== -1; + } + + signIn(auth, userService) { + this.auth = auth; + console.info("SignIn::"); + console.info(auth); + userService.userPromise(auth).then((user) => { + if (!user) { + console.info("SignIn error"); + this.user = null; + return Promise.reject(); + } + console.info("SignIn user::"); + this.user = user; + emitter.emitConnected(user); + console.info(user); + return user; + }); + + } + + signOut() { + delete this.auth; + delete this.user; } } diff --git a/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag b/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag index 5a943d8..9806476 100644 --- a/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag +++ b/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag @@ -17,18 +17,23 @@ require("./PollVoters.tag"); <div> <CreatePollHeader/> <div> - <PollDescription if="{step == 0}"/> - <PollChoicesText if="{step == 1 && type == 'text'}"/> - <PollChoicesImage if="{step == 1 && type == 'image'}"/> - <PollChoicesDate if="{step == 1 && type == 'date'}"/> - <PollSettings if="{step == 2}"/> - <PollVoters if="{step == 3}"/> + <PollDescription show="{step == 0}"/> + <PollChoicesText show="{step == 1 && type == 'text'}"/> + <PollChoicesImage show="{step == 1 && type == 'image'}"/> + <PollChoicesDate show="{step == 1 && type == 'date'}"/> + <PollSettings show="{step == 2}"/> + <PollVoters show="{step == 3}"/> </div> </div> <script> this.type = this.opts.type; this.step = form.step; + if (session.isConnected()) { + form.init(session.user); + } else { + form.init(); + } form.onStepChanged(step => { this.step = step; try { diff --git a/pollen-ui-riot-js/src/main/web/tag/CreatePollHeader.tag b/pollen-ui-riot-js/src/main/web/tag/CreatePollHeader.tag index 7f12a18..4bfd050 100644 --- a/pollen-ui-riot-js/src/main/web/tag/CreatePollHeader.tag +++ b/pollen-ui-riot-js/src/main/web/tag/CreatePollHeader.tag @@ -49,8 +49,9 @@ let form = require("../js/PollForm"); border-bottom: 1px solid #b2c7d3; } - .body-container > div { - + .container > div { + margin-left: 12px; + margin-right: 12px; } .selectedTab { diff --git a/pollen-ui-riot-js/src/main/web/tag/Header.tag b/pollen-ui-riot-js/src/main/web/tag/Header.tag index 8fa6d00..7da95ea 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Header.tag +++ b/pollen-ui-riot-js/src/main/web/tag/Header.tag @@ -40,12 +40,8 @@ require("./HeaderI18n.tag"); this.user = null; - if (authService.isConnected()) { - authService.getUser() - .then((user) => { - this.user = user; - this.update(); - }, this.signOut); + if (session.isConnected()) { + this.user = session.user; } emitter.onConnected((user) => { diff --git a/pollen-ui-riot-js/src/main/web/tag/PollChoiceText.tag b/pollen-ui-riot-js/src/main/web/tag/PollChoiceText.tag new file mode 100644 index 0000000..a20c03d --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/PollChoiceText.tag @@ -0,0 +1,39 @@ +<PollChoiceText> + + <div class="container"> + <label class="wide" for="choice{number}">Choix {number}</label> + <label if="{number == 1 }">Description</label> + </div> + <div class="container"> + + <input class="wide" if="{number == 1}" type="text" required ref="choice{number}" name="choice{number}" + id="choice{number}" + value="{(choices[0] || {text:''}).text}"> + <input class="wide" if="{number > 1}" type="text" ref="choice{number}" name="choice{number}" id="choice{number}" + value="{(choices[number - 1] || {text:''}).text}"> + <input class="wider" type="text" ref="description{number}" name="description{number}" id="description{number}" + value="{(choices[number - 1] || {description:''}).description}"> + </div> + + <script> + this.number = opts.number; + this.choices = opts.choices; + </script> + + <style> + .wide { + width: 440px; + } + + .wider { + width: 640px; + } + + .container { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + } + </style> +</PollChoiceText> \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/tag/PollChoiceTextGroup.tag b/pollen-ui-riot-js/src/main/web/tag/PollChoiceTextGroup.tag new file mode 100644 index 0000000..026cd3c --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/PollChoiceTextGroup.tag @@ -0,0 +1,14 @@ +require('./PollChoiceText.tag'); +<PollChoiceTextGroup> + <PollChoiceText number="{start}" choices="{choices}"/> + <PollChoiceText number="{start + 1}" choices="{choices}"/> + <PollChoiceText number="{start + 2}" choices="{choices}"/> + <PollChoiceText number="{start + 3}" choices="{choices}"/> + <PollChoiceText number="{start + 4}" choices="{choices}"/> + + <script> + this.choices = opts.choices; + this.descriptions = opts.descriptions; + this.start = parseInt(opts.start); + </script> +</PollChoiceTextGroup> \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/tag/PollChoicesText.tag b/pollen-ui-riot-js/src/main/web/tag/PollChoicesText.tag index a4a76ff..8f07fde 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollChoicesText.tag +++ b/pollen-ui-riot-js/src/main/web/tag/PollChoicesText.tag @@ -1,35 +1,88 @@ let form = require("../js/PollForm"); +require('./PollChoiceTextGroup.tag'); <PollChoicesText> - <div> - Choix du sondage (type texte) - </div> - <div class="actions"> - <a class="button" onclick="{previousStep}">Précédent</a> - <a class="button" onclick="{nextStep}">Suivant</a> - </div> + <form ref="choices" onsubmit="{nextStep}"> + <virtual each={item in counts}> + <PollChoiceTextGroup choices="{form.model.textChoices}" start="{item - 4}"/> + </virtual> + <div class="actions"> + <a class="button" onclick="{addMoreChoices}"> <i class="fa fa-plus"/>Plus de choix</a> + <a class="button" onclick="{previousStep}">Précédent</a> + <input type="submit" class="button" value="Suivant"> + </div> + </form> <script> + this.counts = [5]; + this.count = 5; + this.form = form; + + this.on('mount', () => { + this.choices = this.refs.choices; + }); + + form.onStepChanged(step => { + if (step == 1) { + let choices = this.form.model.textChoices; + console.info("init step1 with " + choices.length + " choices"); + console.info(choices); + this.counts = []; + this.count = 0; + let i; + for (i = 0; i < choices.length; i++) { + if (i > 0 && i % 5 == 0) { + this._addChoices(i); + } + } + if (i <= 5 || i % 5 > 0) { + this._addChoices(this.count + 5); + } + console.info("Final count: " + this.count); + this.update(); + } + }); + this.previousStep = (e) => { + form.fromTextChoices(this.choices); form.previousStep(); }; this.nextStep = (e) => { + e.preventDefault(); + e.stopPropagation(); + form.fromTextChoices(this.choices); form.nextStep(); }; + this.addMoreChoices = () => { + this._addChoices(this.count + 5); + this.update({counts: this.counts}); + }; + + this._addChoices = (i) => { + this.count = i; + this.counts.push(i); + }; </script> <style> - .actions { - margin-top: 50px; + + a.button > i { margin-right: 10px; - margin-left: 10px; - margin-bottom: 10px; + } + + .actions { + margin: 50px 10px 10px; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; } + .actions > a { margin: 5px; } + + .actions > input { + margin: 5px; + } </style> </PollChoicesText> \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag b/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag index 34136b1..a4d9020 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag +++ b/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag @@ -2,32 +2,52 @@ let form = require("../js/PollForm"); let route = require("riot-route"); <PollDescription> - <div> - Description du sondage - </div> - - <div class="actions"> - <a class="button" onclick="{cancel}">Annuler</a> - <a class="button" onclick="{nextStep}">Suivant</a> - </div> + <form onsubmit="{nextStep}"> + <label for="title">Titre du sondage</label> + <input ref="title" type="text" required name="title" id="title" value="{model.title}" placeholder="Enter le titre du sondage"> + <label for="name">Votre nom</label> + <input ref="name" type="text" required name="name" id="name" value="{model.name}" placeholder="Enter votre nom"> + <label for="email">Votre courriel</label> + <input ref="email" type="email" required name="email" id="email" value="{model.email}" placeholder="Enter votre courriel"> + <div class="actions"> + <a class="button" onclick="{cancel}">Annuler</a> + <input type="submit" class="button" value="Suivant"> + </div> + </form> <script> - this.nextStep = (e) => { form.nextStep(); }; - this.cancel = (e) => { route("/", null, true); }; + this.model = form.model; + this.nextStep = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.model.title = this.refs.title.value; + this.model.name = this.refs.name.value; + this.model.email = this.refs.email.value; + form.nextStep(); + }; + this.cancel = () => { + route("/", null, true); + }; </script> <style> + form > input { + width: 440px; + } + .actions { - margin-top: 50px; - margin-right: 10px; - margin-left: 10px; - margin-bottom: 10px; + margin: 50px 10px 10px; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; } + .actions > a { margin: 5px; } + + .actions > input { + margin: 5px; + } </style> </PollDescription> \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag index 1f5401e..b6f38ca 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag @@ -1,8 +1,8 @@ let authService = require("../js/AuthService"); let session = require("../js/Session"); let emitter = require("../js/EmitterService"); -require("./popup/NewPassword.tag"); let route = require("riot-route"); +require("./popup/NewPassword.tag"); <SignIn> <div class="body-container"> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 99f26655168eadd0894cd76bbfe4dcd40aeb621a Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 08:39:27 2017 +0100 Use same configuration as default bundle application for dev --- pollen-rest-api/pom.xml | 25 +------------------------ pollen-ui-riot-js/src/main/web/conf.json | 2 +- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/pollen-rest-api/pom.xml b/pollen-rest-api/pom.xml index ed76250..de336ad 100644 --- a/pollen-rest-api/pom.xml +++ b/pollen-rest-api/pom.xml @@ -238,29 +238,6 @@ <pluginManagement> <plugins> <plugin> - <groupId>org.mortbay.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <configuration> - <stopKey>B</stopKey> - <stopPort>1270</stopPort> - <contextXml>${basedir}/src/jetty/jetty-context.xml</contextXml> - <webAppConfig> - <contextPath>/${defaultWebContextPath}</contextPath> - </webAppConfig> - <systemProperties> - <systemProperty> - <name>testDirectory</name> - <value>${defaultLogDir}</value> - </systemProperty> - <systemProperty> - <name>pollen.data.directory</name> - <value>${defaultDbDir}</value> - </systemProperty> - </systemProperties> - </configuration> - </plugin> - - <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> @@ -270,7 +247,7 @@ <pollen.log.dir>${defaultLogDir}</pollen.log.dir> </systemProperties> <uriEncoding>UTF-8</uriEncoding> - <port>8084</port> + <port>8888</port> </configuration> </plugin> </plugins> diff --git a/pollen-ui-riot-js/src/main/web/conf.json b/pollen-ui-riot-js/src/main/web/conf.json index eaace3f..78dd34b 100644 --- a/pollen-ui-riot-js/src/main/web/conf.json +++ b/pollen-ui-riot-js/src/main/web/conf.json @@ -1,5 +1,5 @@ { - "endPoint": "http://localhost:8084/pollen-rest-api", + "endPoint": "http://localhost:8888/pollen-rest-api", "pollDefaultPageSize": 10, "commentDefaultPageSize": 10, "favoriteListDefaultPageSize": 15, -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit b0e0ac1cca44ba5c2f8704e618d1b1ad425b1db9 Author: Tony CHEMIT <dev@tchemit.fr> Date: Sat Jan 14 14:41:39 2017 +0100 Amélioration i18n + utilisation base par défaut sinon certaines pages ne sont pas accessibles en direct --- pollen-ui-riot-js/src/main/web/i18n.json | 186 ++++++++++----------- pollen-ui-riot-js/src/main/web/index.js | 1 - pollen-ui-riot-js/src/main/web/js/I18nHelper.js | 48 ++---- pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag | 1 + pollen-ui-riot-js/src/main/web/tag/Footer.tag | 10 +- pollen-ui-riot-js/src/main/web/tag/Header.tag | 17 +- pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag | 2 +- pollen-ui-riot-js/src/main/web/tag/Home.tag | 6 +- .../src/main/web/tag/PollDescription.tag | 2 +- pollen-ui-riot-js/src/main/web/tag/Pollen.tag | 7 +- pollen-ui-riot-js/src/main/web/tag/SignCheck.tag | 82 ++++++++- pollen-ui-riot-js/src/main/web/tag/SignIn.tag | 16 +- pollen-ui-riot-js/src/main/web/tag/SignUp.tag | 18 +- .../src/main/web/tag/popup/AccountCreated.tag | 10 +- .../src/main/web/tag/popup/NewPassword.tag | 10 +- .../src/main/web/tag/popup/ResendValidation.tag | 10 +- 16 files changed, 245 insertions(+), 181 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index afaac9b..8a82321 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -1,102 +1,100 @@ { "fr": { - "signup.title": "Créer un compte", - "signup.email": "Email", - "signup.email.placeholder": "Entrer l'email", - "signup.name": "Nom", - "signup.name.placeholder": "Entrer votre nom d'utilisateur", - "signup.validate": "Valider", - "signup.resendValidation": "Déja inscrit, mais compte non validé ?", - "signup.error": "Impossible d'enregister le compte.", - "signup.error.email": "L'adresse email est déjà utilisé pour un autre compte.", - "signup.createAccount.title": "Votre compte a bien été créé", - "signup.createAccount.description": "Un courriel vous a été envoyé avec vos identifiants ainsi que l'url de validation de votre compte.", - "signup.createAccount.validate": "Continuer", - "resendvalidation.title": "Renvoyer un courriel de validation de compte", - "resendvalidation.action": "Envoyer", - "resendvalidation.placeholder": "Entrer votre courriel", - "resendvalidation.sent": "Un nouveau courriel d'invitation a été envoyé", - "resendvalidation.error.emailNotFound": "Le courriel n'a pas été trouvé", - "signin.title": "Déjà membre ?", - "signin.login": "Email", - "signin.login.placeholder": "Entrer l'email", - "signin.password": "Mot de passe", - "signin.password.placeholder": "Entrer le mot de passe", - "signin.lostpassword": "Mot de passe perdu ?", - "signin.connexion": "Se connecter", - "signin.error.signin": "Courriel ou de mot de passe invalide", - "newpassword.title": "Obtenir un nouveau mot de passe", - "newpassword.action": "Envoyer", - "newpassword.placeholder": "Entrer votre courriel", - "newpassword.error.emailNotFound": "Le courriel n'a pas été trouvé", - "newpassword.sent": "Un nouveau mot de passe vient d'être envoyé", - "footer.doc": "Pollen 2.0", - "footer.download": "Télécharger", - "footer.contact": "Nous contacter", - "footer.participate": "Contribuer au projet", - "footer.license": "Licence", - "header.signin": "Vous connecter", - "header.signup": "Vous inscrire", - "header.signout": "Se déconnecter", - "header.home": "Accueil", - "header.i18n.lang": "Langue", - "header.myProfile": "Mon profile", - "header.myPolls": "Mes sondages", - "header.myFavoriteLists": "Mes listes de favoris", - "home.createTextPoll":"", - "home.createImagePoll":"", - "home.createDatePoll":"", - ".": "", + "signup_title": "Créer un compte", + "signup_email": "Email", + "signup_email_placeholder": "Entrer l'email", + "signup_name": "Nom", + "signup_name_placeholder": "Entrer votre nom d'utilisateur", + "signup_validate": "Valider", + "signup_resendValidation": "Déja inscrit, mais compte non validé ?", + "signup_error": "Impossible d'enregister le compte.", + "signup_error_email": "L'adresse email est déjà utilisé pour un autre compte.", + "createaccount_title": "Votre compte a bien été créé", + "createaccount_description": "Un courriel vous a été envoyé avec vos identifiants ainsi que l'url de validation de votre compte.", + "createaccount_action": "Continuer", + "resendvalidation_title": "Renvoyer un courriel de validation de compte", + "resendvalidation_action": "Envoyer", + "resendvalidation_placeholder": "Entrer votre courriel", + "resendvalidation_sent": "Un nouveau courriel d'invitation a été envoyé", + "resendvalidation_error_emailNotFound": "Le courriel n'a pas été trouvé", + "signin_title": "Déjà membre ?", + "signin_login": "Email", + "signin_login_placeholder": "Entrer l'email", + "signin_password": "Mot de passe", + "signin_password_placeholder": "Entrer le mot de passe", + "signin_lostpassword": "Mot de passe perdu ?", + "signin_connexion": "Se connecter", + "signin_error_signin": "Courriel ou de mot de passe invalide", + "newpassword_title": "Obtenir un nouveau mot de passe", + "newpassword_action": "Envoyer", + "newpassword_placeholder": "Entrer votre courriel", + "newpassword_error_emailNotFound": "Le courriel n'a pas été trouvé", + "newpassword_sent": "Un nouveau mot de passe vient d'être envoyé", + "footer_doc": "Pollen 2.0", + "footer_download": "Télécharger", + "footer_contact": "Nous contacter", + "footer_participate": "Contribuer au projet", + "footer_license": "Licence", + "header_signin": "Vous connecter", + "header_signup": "Vous inscrire", + "header_signout": "Se déconnecter", + "header_home": "Accueil", + "header_i18n_lang": "Langue", + "header_myProfile": "Mon profile", + "header_myPolls": "Mes sondages", + "header_myFavoriteLists": "Mes listes de favoris", + "home_createTextPoll": "Créer un sondage de type text", + "home_createImagePoll": "Créer un sondage de type image", + "home_createDatePoll": "Créer un sondage de type date", "": "" }, "en": { - "signup.title": "Create an account", - "signup.email": "Email", - "signup.email.placeholder": "Enter your email", - "signup.name": "User name", - "signup.name.placeholder": "Entrer your user name", - "signup.validate": "Create", - "signup.resendValidation": "Already member, but account never validated ?", - "signup.error": "Could not register account.", - "signup.error.email": "This email is already used.", - "signup.createAccount.title": "Your account was created", - "signup.createAccount.description": "We sent you an email with the account validation process and your authentication data.", - "signup.createAccount.validate": "Continue", - "resendvalidation.title": "Send another validation email", - "resendvalidation.action": "Send again", - "resendvalidation.sent": "A new invitation email was sent", - "resendvalidation.placeholder": "Fill your email", - "resendvalidation.error.emailNotFound": "Your email was not found", - "signin.title": "Already member?", - "signin.login": "Email", - "signin.login.placeholder": "Entrer your email", - "signin.password": "Password", - "signin.password.placeholder": "Entrer your password", - "signin.lostpassword": "Lost password?", - "signin.connexion": "Connect", - "signin.error.signin": "Email or password invalid", - "newpassword.placeholder": "Fill your email", - "newpassword.title": "Get a new password", - "newpassword.action": "Send password", - "newpassword.error.emailNotFound": "Your email was not found", - "newpassword.sent": "A new password was sent", - "footer.doc": "Pollen 2.0", - "footer.download": "Télécharger", - "footer.contact": "Nous contacter", - "footer.participate": "Contribuer au projet", - "footer.license": "Licence", - "header.signin": "SignIn", - "header.signup": "SignUp", - "header.signout": "Disconnect", - "header.home": "Home", - "header.i18n.lang": "Language", - "header.myProfile": "My profile", - "header.myPolls": "My polls", - "header.myFavoriteLists": "My favorite lists", - "home.createTextPoll":"Create a text poll", - "home.createImagePoll":"Create a image poll", - "home.createDatePoll":"Create a date poll", - ".": "", + "signup_title": "Create an account", + "signup_email": "Email", + "signup_email_placeholder": "Enter your email", + "signup_name": "User name", + "signup_name_placeholder": "Entrer your user name", + "signup_validate": "Create", + "signup_resendValidation": "Already member, but account never validated ?", + "signup_error": "Could not register account.", + "signup_error_email": "This email is already used.", + "createdaccount_title": "Your account was created", + "createdaccount_description": "We sent you an email with the account validation process and your authentication data.", + "createdaccount_action": "Continue", + "resendvalidation_title": "Send another validation email", + "resendvalidation_action": "Send again", + "resendvalidation_sent": "A new invitation email was sent", + "resendvalidation_placeholder": "Fill your email", + "resendvalidation_error_emailNotFound": "Your email was not found", + "signin_title": "Already member?", + "signin_login": "Email", + "signin_login_placeholder": "Entrer your email", + "signin_password": "Password", + "signin_password_placeholder": "Entrer your password", + "signin_lostpassword": "Lost password?", + "signin_connexion": "Connect", + "signin_error_signin": "Email or password invalid", + "newpassword_placeholder": "Fill your email", + "newpassword_title": "Get a new password", + "newpassword_action": "Send password", + "newpassword_error_emailNotFound": "Your email was not found", + "newpassword_sent": "A new password was sent", + "footer_doc": "Pollen 2.0", + "footer_download": "Download", + "footer_contact": "Contact us", + "footer_participate": "Get involved!", + "footer_license": "Licence", + "header_signin": "SignIn", + "header_signup": "SignUp", + "header_signout": "Disconnect", + "header_home": "Home", + "header_i18n_lang": "Language", + "header_myProfile": "My profile", + "header_myPolls": "My polls", + "header_myFavoriteLists": "My favorite lists", + "home_createTextPoll": "Create a text poll", + "home_createImagePoll": "Create a image poll", + "home_createDatePoll": "Create a date poll", "": "" } } \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/index.js b/pollen-ui-riot-js/src/main/web/index.js index 430ec69..d25dda0 100644 --- a/pollen-ui-riot-js/src/main/web/index.js +++ b/pollen-ui-riot-js/src/main/web/index.js @@ -9,5 +9,4 @@ require("./tag/Pollen.tag"); riot.mount("*"); let route = require("riot-route"); -route.base("/"); route.start(true); diff --git a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js index a6de843..6d3143f 100644 --- a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js +++ b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js @@ -4,50 +4,30 @@ module.exports = { this.generateBundle(locale, value); emitter.onLocaleChanged((locale) => { this.generateBundle(locale, value); - this.update(); + try { + this.update(); + } catch (e) { + console.error("Error in generateBundle for " + value, e); + } }); }, generateBundle(locale, value) { - this.prefix = value; - - this.bundle = this.bundles[locale]; - Object.keys(this.bundle).forEach((key) => { - if (key.startsWith(value + ".")) { - - let path = key.split("."); - path.shift(); - let first = path.shift(); - this["__" + first] = this["__" + first] || {}; + let bundle = this.bundles[locale]; + this.__ = {}; + Object.keys(bundle).forEach((key) => { + if (key.startsWith(value + "_")) { - let last = path.pop(); - if (!last) { - let descriptor = Object.getOwnPropertyDescriptor(this, "__" + first + "__"); - if (!descriptor) { - Object.defineProperty(this, "__" + first + "__", {get: () => this.bundle[key]}); - } - - } else { - let v = path.reduce((a, b) => { - a[b] = a[b] || {}; - return a[b]; - }, this["__" + first]); - let descriptor = Object.getOwnPropertyDescriptor(v, last + "__"); - if (!descriptor) { - Object.defineProperty(v, last + "__", {get: () => this.bundle[key]}); - } - } + let realKey = key.substring(value.length + 1); + this.__[realKey] = bundle[key]; + console.info(realKey + " -> " + this.__[realKey]); } }); }, - t(key, ...params) { - return this.l(this.prefix + "." + key, ...params); - }, - - l(key, ...params) { - return this.format(this.bundle[key], params); + __(key, ...params) { + return this.format(__[key], ...params); }, format(value, params) { diff --git a/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag b/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag index 9806476..91a4d9a 100644 --- a/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag +++ b/pollen-ui-riot-js/src/main/web/tag/CreatePoll.tag @@ -40,6 +40,7 @@ require("./PollVoters.tag"); this.update() } catch (e) { //FIXME J'ai une erreur, mais je ne sais pas quoi en faire... + console.error("Could not update on Create poll: ", e); } }); </script> diff --git a/pollen-ui-riot-js/src/main/web/tag/Footer.tag b/pollen-ui-riot-js/src/main/web/tag/Footer.tag index 2a35b86..d514deb 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Footer.tag +++ b/pollen-ui-riot-js/src/main/web/tag/Footer.tag @@ -2,11 +2,11 @@ let session = require("../js/Session"); let emitter = require("../js/EmitterService"); <footer> <div class="links"> - <a href="https://pollen.chorem.org/v/latest/index.html">{__doc__}</a> - <a href="https://forge.chorem.org/projects/pollen/files">{__download__}</a> - <a href="http://list.chorem.org/cgi-bin/mailman/listinfo/pollen-users">{__contact__}</a> - <a href="https://forge.chorem.org/projects/pollen">{__participate__}</a> - <a href="http://www.gnu.org/licenses/agpl.html">{__license__}</a> + <a href="https://pollen.chorem.org/v/latest/index.html">{__.doc}</a> + <a href="https://forge.chorem.org/projects/pollen/files">{__.download}</a> + <a href="http://list.chorem.org/cgi-bin/mailman/listinfo/pollen-users">{__.contact}</a> + <a href="https://forge.chorem.org/projects/pollen">{__.participate}</a> + <a href="http://www.gnu.org/licenses/agpl.html">{__.license}</a> <a href="http://www.codelutin.com/" target="_blank">Code Lutin</a> </div> <script> diff --git a/pollen-ui-riot-js/src/main/web/tag/Header.tag b/pollen-ui-riot-js/src/main/web/tag/Header.tag index 7da95ea..ff258f6 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Header.tag +++ b/pollen-ui-riot-js/src/main/web/tag/Header.tag @@ -6,21 +6,21 @@ require("./HeaderI18n.tag"); <Header> <div class="header-home"> - <a class="header-link" href="/" target="_top">{__home__}</a> + <a class="header-link" href="#home" target="_top">{__.home}</a> </div> <div class="header-separator"></div> <div class="header-space"></div> - <a class="button header-button header-signin" if="{!user}" href="/signin">{__signin__}</a> + <a class="button header-button header-signin" if="{!user}" href="#signin">{__.signin}</a> - <a class="button header-button header-signup" if="{!user}" href="/signup">{__signup__}</a> + <a class="button header-button header-signup" if="{!user}" href="#signup">{__.signup}</a> <div if="{user}" class="dropdown"> <a class="header-link">{user.email}</a> <div class="dropdown-content"> - <a href="/user/profile">{__myProfile__}</a> - <a href="/user/polls">{__myPolls__}</a> - <a href="/user/favoriteLists">{__myFavoriteLists__}</a> + <a href="#user/profile">{__.myProfile}</a> + <a href="#user/polls">{__.myPolls}</a> + <a href="#user/favoriteLists">{__.myFavoriteLists}</a> <span role="separator" class="divider"></span> - <a onclick="{signOut}">{__signout__}</a> + <a onclick="{signOut}">{__.signout}</a> </div> </div> <div class="header-separator"></div> @@ -31,8 +31,7 @@ require("./HeaderI18n.tag"); this.signOut = () => { let callback = () => { this.user = null; - this.update(); - route("/"); + route("home"); }; authService.signOut().then(callback, callback); diff --git a/pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag b/pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag index 0a2b145..4c5bec2 100644 --- a/pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag +++ b/pollen-ui-riot-js/src/main/web/tag/HeaderI18n.tag @@ -15,7 +15,7 @@ let emitter = require("../js/EmitterService"); <script> this.locale = session.locale; //FIXME Le traduction ne se fait pas - this.generateBundle(session.locale, "header.i18n"); + this.generateBundle(session.locale, "header_i18n"); this.toEnglish = () => { if ('en' != session.locale) { session.locale = 'en'; diff --git a/pollen-ui-riot-js/src/main/web/tag/Home.tag b/pollen-ui-riot-js/src/main/web/tag/Home.tag index e007029..4fb2fbd 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Home.tag +++ b/pollen-ui-riot-js/src/main/web/tag/Home.tag @@ -7,9 +7,9 @@ let route = require("riot-route"); <div class="body-container"> <div class="split"> - <div onclick="{createText}"><a href="/poll/new/text">Créer un sondage de type texte</a></div> - <div onclick="{createImage}"><a href="/poll/new/image">Créer un sondage de type image</a></div> - <div onclick="{createDate}"><a href="/poll/new/date">Créer un sondage de type date</a></div> + <div onclick="{createText}"><a href="/poll/new/text">{__.createTextPoll}</a></div> + <div onclick="{createImage}"><a href="/poll/new/image">{__.createImagePoll}</a></div> + <div onclick="{createDate}"><a href="/poll/new/date">{__.createDatePoll}</a></div> </div> </div> diff --git a/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag b/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag index a4d9020..82d5071 100644 --- a/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag +++ b/pollen-ui-riot-js/src/main/web/tag/PollDescription.tag @@ -26,7 +26,7 @@ let route = require("riot-route"); form.nextStep(); }; this.cancel = () => { - route("/", null, true); + route("home", null, true); }; </script> <style> diff --git a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag index e8c2b2a..f9100c5 100644 --- a/pollen-ui-riot-js/src/main/web/tag/Pollen.tag +++ b/pollen-ui-riot-js/src/main/web/tag/Pollen.tag @@ -25,8 +25,11 @@ let emitter = require("../js/EmitterService"); route("/signup", () => { riot.mount(this.refs.content, "signup"); }); + route("/signup/validate", () => { + riot.mount(this.refs.content, "signup", {validate: true}); + }); route("/signcheck/*/*", (id, token) => { - riot.mount(this.refs.content, "signcheck", {id, token}); + riot.mount(this.refs.content, "signcheck", {id: id, token: token}); }); route("/poll", () => { riot.mount(this.refs.content, "polls"); @@ -46,7 +49,7 @@ let emitter = require("../js/EmitterService"); route("/poll/new/*", (type) => { riot.mount(this.refs.content, "createpoll", {type: type}); }); - route(() => { + route( () => { riot.mount(this.refs.content, "home"); }); diff --git a/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag b/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag index 20e0b7a..b0daf05 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag @@ -5,13 +5,93 @@ let route = require("riot-route"); <SignCjeck> <div class="body-container"> - <%--TODO--%> + <div class="body-container"> + <form class="signcheck" method="post" onsubmit="{signIn}"> + <div class="split"> + <div class="legend"> + <i class="fa fa-user fa-3x"> </i>{__title__} + </div> + <div>{__message__}</div> + <br/> + <a class="button" href="/signin">{__signin__}</a> + <a class="button" href="/signup/validate">{__resendValidation__}</a> + + <div class="{error ? 'error' : 'info'}">{message}</div> + </div> + </form> + </div> + </div> <script> this.installBundle(session.locale, "signcheck", emitter); + this.message = "Votre compte est en cours de validation..."; + this.error = false; + authService.validateEmail(opts.id, opts.permission) + .then(() => { + this.message = "Votre compte a été validé"; + this.update(); + }) + .catch(() => { + this.error = true; + this.message = "Votre compte n'a pas pu être validé"; + this.update(); + }); + </script> + <style scoped> + + .wide { + width: 320px; + } + + .button { + margin: 5px 0; + } + + .signcheck { + display: flex; + justify-content: space-around; + background: white; + border: solid 2px #c8ccca; + padding: 45px 0; + border-radius: 10px; + text-align: center; + margin: 40px 0; + width: 400px; + } + + .legend { + width: 100%; + height: 70px; + border-bottom: 1px solid #b2c7d3; + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 30px; + font-size: 20px; + } + + .split { + flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + .info { + margin: 3px; + color: #13a2ff; + } + + .error { + margin: 3px; + color: red; + } + </style> + </SignCjeck> diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag index b6f38ca..8460923 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag @@ -9,17 +9,17 @@ require("./popup/NewPassword.tag"); <form class="signin" method="post" onsubmit="{signIn}"> <div class="split"> <div class="legend"> - <i class="fa fa-user fa-3x"> </i>{__title__} + <i class="fa fa-user fa-3x"> </i>{__.title} </div> - <label class="wide" for="login">{__login__}</label> + <label class="wide" for="login">{__.login}</label> <input class="wide" type="text" id="login" name="login" ref="login" required - placeholder="{__login.placeholder__}"> - <label class="wide" for="password">{__password__}</label> + placeholder="{__.login_placeholder}"> + <label class="wide" for="password">{__.password}</label> <input class="wide" type="password" id="password" name="password" ref="password" required - placeholder="{__password.placeholder__}"> - <a onclick="{newPassword}">{__lostpassword__}</a> + placeholder="{__.password_placeholder}"> + <a onclick="{newPassword}">{__.lostpassword}</a> <br/> - <input type="submit" class="button" value="{__connexion__}"> + <input type="submit" class="button" value="{__.connexion}"> <div>{message}</div> </div> </form> @@ -46,7 +46,7 @@ require("./popup/NewPassword.tag"); route(this.opts.link || "/"); }) .catch((code) => { - this.message = this.t("error.signin"); + this.message = this.t("error_signin"); this.update(); }); }; diff --git a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag index 0f88949..c704082 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag @@ -10,16 +10,16 @@ require("./popup/AccountCreated.tag"); <div class="body-container"> <form ref="user" class="signup" method="post" onsubmit="{signUp}"> <div class="split"> - <div class="legend"><i class="fa fa-user-plus fa-2x"> </i>{__title__}</div> - <label class="wide" for="name">{__name__}</label> + <div class="legend"><i class="fa fa-user-plus fa-2x"> </i>{__.title}</div> + <label class="wide" for="name">{__.name}</label> <div if="{errors.name}">{errors.name}</div> - <input class="wide" type="text" name="name" id="name" placeholder="{__name.placeholder__}" required> - <label class="wide" for="email">{__email__}</label> + <input class="wide" type="text" name="name" id="name" placeholder="{__.name_placeholder}" required> + <label class="wide" for="email">{__.email}</label> <div if="{errors.email}">{errors.email}</div> - <input class="wide" type="text" name="email" id="email" placeholder="{__email.placeholder__}" required> - <a onclick="{resendValidation}">{__resendValidation__}</a> + <input class="wide" type="text" name="email" id="email" placeholder="{__.email_placeholder}" required> + <a onclick="{resendValidation}">{__.resendValidation}</a> <br/> - <input type="submit" class="button" value="{__validate__}"> + <input type="submit" class="button" value="{__.validate}"> </div> </form> </div> @@ -53,6 +53,9 @@ require("./popup/AccountCreated.tag"); }); }; + if (opts.validate) { + this.resendValidation(); + } </script> <style scoped> @@ -87,6 +90,7 @@ require("./popup/AccountCreated.tag"); margin-bottom: 30px; font-size: 20px; } + .split { flex-grow: 1; display: flex; diff --git a/pollen-ui-riot-js/src/main/web/tag/popup/AccountCreated.tag b/pollen-ui-riot-js/src/main/web/tag/popup/AccountCreated.tag index 783db23..9a8b5ef 100644 --- a/pollen-ui-riot-js/src/main/web/tag/popup/AccountCreated.tag +++ b/pollen-ui-riot-js/src/main/web/tag/popup/AccountCreated.tag @@ -10,16 +10,16 @@ let route = require("riot-route"); <div class="popup-close" onclick="{close}"> <i class="fa fa-times"></i> </div> - <div class="popup-title">{__title__}</div> + <div class="popup-title">{__.title}</div> <div class="popup-message"> - <div>{__description__}</div> - <a class="button" onclick="{action}">Continuer</a> + <div>{__.description}</div> + <a class="button" onclick="{action}">{__.action}</a> </div> </div> <script> - this.installBundle(session.locale, "signin.createAccount", emitter); + this.installBundle(session.locale, "createdaccount", emitter); this.oldParent = this.parent.root; @@ -36,7 +36,7 @@ let route = require("riot-route"); }; this.action = () => { this.close(); - route("/home", null, true); + route("home", null, true); }; </script> diff --git a/pollen-ui-riot-js/src/main/web/tag/popup/NewPassword.tag b/pollen-ui-riot-js/src/main/web/tag/popup/NewPassword.tag index 6ff1515..af16ac7 100644 --- a/pollen-ui-riot-js/src/main/web/tag/popup/NewPassword.tag +++ b/pollen-ui-riot-js/src/main/web/tag/popup/NewPassword.tag @@ -10,14 +10,14 @@ let authService = require("../../js/AuthService"); <div class="popup-close" onclick="{close}"> <i class="fa fa-times"></i> </div> - <div class="popup-title">{__title__}</div> + <div class="popup-title">{__.title}</div> <form class="popup-message" onsubmit="{action}"> <div class="popup-message-header"> - <div class="send" if="{sent}"><i class="fa fa-envelope"></i> {__sent__}</div> + <div class="send" if="{sent}"><i class="fa fa-envelope"></i> {__.sent}</div> <div if="{error}" class="error">{error}</div> </div> - <input ref="email" type="text" required placeholder="{__placeholder__}"> - <input type="submit" class="button" value="{__action__}"> + <input ref="email" type="text" required placeholder="{__.placeholder}"> + <input type="submit" class="button" value="{__.action}"> </form> </div> @@ -58,7 +58,7 @@ let authService = require("../../js/AuthService"); this.update(); }) .catch(() => { - this.error = this.t("error.emailNotFound"); + this.error = __.error_emailNotFound; this.update(); }); } diff --git a/pollen-ui-riot-js/src/main/web/tag/popup/ResendValidation.tag b/pollen-ui-riot-js/src/main/web/tag/popup/ResendValidation.tag index 5174263..05bfdbf 100644 --- a/pollen-ui-riot-js/src/main/web/tag/popup/ResendValidation.tag +++ b/pollen-ui-riot-js/src/main/web/tag/popup/ResendValidation.tag @@ -10,14 +10,14 @@ let authService = require("../../js/AuthService"); <div class="popup-close" onclick="{close}"> <i class="fa fa-times"></i> </div> - <div class="popup-title">{__title__}</div> + <div class="popup-title">{__.title}</div> <form class="popup-message" onsubmit="{action}"> <div class="popup-message-header"> - <div class="send" if="{sent}"><i class="fa fa-envelope"></i> {__sent__}</div> + <div class="send" if="{sent}"><i class="fa fa-envelope"></i> {__.sent}</div> <div if="{error}" class="error">{error}</div> </div> - <input ref="email" type="text" required placeholder="{__placeholder__}"> - <input type="submit" class="button" value="{__action__}"> + <input ref="email" type="text" required placeholder="{__.placeholder}"> + <input type="submit" class="button" value="{__.action}"> </form> </div> @@ -58,7 +58,7 @@ let authService = require("../../js/AuthService"); this.update(); }) .catch(() => { - this.error = this.t("error.emailNotFound"); + this.error = __.error_emailNotFound; this.update(); }); } -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit c9359ffbd941d89d4e719953a9955a360be96c1d Author: Tony CHEMIT <dev@tchemit.fr> Date: Sun Jan 15 13:41:37 2017 +0100 Review security and use now cookies to store authentication informations --- .../rest/api/PollenRestApiRequestFilter.java | 85 ++++++++- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 52 +++++- pollen-rest-api/src/main/resources/mapping | 1 + pollen-rest-api/src/main/webapp/WEB-INF/web.xml | 35 +++- pollen-services/pom.xml | 5 + pollen-services/src/main/config/PollenServices.ini | 16 +- .../security/DefaultPollenSecurityContext.java | 1 + ...xt.java => MissingAuthenticationException.java} | 28 +-- .../security/PollenCypherTechnicalException.java | 16 ++ .../service/security/PollenSecurityContext.java | 2 + .../services/service/security/SecurityService.java | 202 ++++++++++++++++++--- .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + .../service/PollenUIUrlRenderServiceTest.java | 14 +- pollen-ui-riot-js/src/main/web/index.js | 7 +- pollen-ui-riot-js/src/main/web/js/AuthService.js | 17 +- pollen-ui-riot-js/src/main/web/js/FetchService.js | 7 - pollen-ui-riot-js/src/main/web/js/I18nHelper.js | 4 + pollen-ui-riot-js/src/main/web/js/Session.js | 9 +- pollen-ui-riot-js/src/main/web/tag/SignIn.tag | 2 +- pom.xml | 13 +- 21 files changed, 408 insertions(+), 110 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java index 72103b6..eb64c6c 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/PollenRestApiRequestFilter.java @@ -28,15 +28,18 @@ import org.chorem.pollen.persistence.PollenPersistenceContext; import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.services.PollenServiceContext; +import org.chorem.pollen.services.service.security.PollenCypherTechnicalException; import org.chorem.pollen.services.service.security.PollenInvalidSessionTokenException; import org.chorem.pollen.services.service.security.PollenSecurityContext; import org.chorem.pollen.services.service.security.SecurityService; import org.debux.webmotion.server.WebMotionFilter; import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.call.CookieManager; import org.debux.webmotion.server.call.HttpContext; import org.debux.webmotion.server.render.Render; import org.debux.webmotion.server.render.RenderStatus; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.util.Locale; import java.util.Map; @@ -52,6 +55,10 @@ public class PollenRestApiRequestFilter extends WebMotionFilter { private static final String HEADER_ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; private static final String HEADER_ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + private static final String COOKIE_POLLEN_AUTH = "pollen-auth"; + private static final String COOKIE_POLLEN_CONNECTED = "pollen-connected"; + private final static int COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year + public static final String REQUEST_PERMISSION_PARAMETER = "permission"; public static final String REQUEST_HEADER_SESSION_TOKEN = "X-Pollen-Session-Token"; @@ -59,9 +66,9 @@ public class PollenRestApiRequestFilter extends WebMotionFilter { private static final Log log = LogFactory.getLog(PollenRestApiRequestFilter.class); @SuppressWarnings("unused") - public void inject(Call call, HttpContext context) throws PollenInvalidSessionTokenException { + public void inject(Call call, HttpContext context) throws PollenInvalidSessionTokenException, PollenCypherTechnicalException { - prepareRequestContext(context); + PollenRestApiRequestContext pollenRestApiRequestContext = prepareRequestContext(context); if (HttpContext.METHOD_OPTIONS.equals(context.getMethod())) { @@ -95,9 +102,49 @@ public class PollenRestApiRequestFilter extends WebMotionFilter { doProcess(); + PollenSecurityContext securityContext = pollenRestApiRequestContext.getSecurityContext(); + if (securityContext.isConnected()) { + + // add auth cookies + + SessionToken sessionToken = securityContext.getSessionToken(); + String value = pollenRestApiRequestContext.getSecurityService().encrypt( + sessionToken.getPollenUser().getTopiaId(), + sessionToken.getPollenToken().getToken() + ); + Cookie authCookie = new Cookie(COOKIE_POLLEN_AUTH, value); + authCookie.setPath("/"); + authCookie.setMaxAge(COOKIE_MAX_AGE); + response.addCookie(authCookie); + + Cookie connectedCookie = new Cookie(COOKIE_POLLEN_CONNECTED, "true"); + connectedCookie.setPath("/"); + connectedCookie.setMaxAge(COOKIE_MAX_AGE); + response.addCookie(connectedCookie); + + if (log.isDebugEnabled()) { + log.debug("Add auth cookie:: " + authCookie.getValue()); + } + + } else { + + // remove auth cookies + + Cookie authCookie = new Cookie(COOKIE_POLLEN_AUTH, ""); + authCookie.setPath("/"); + authCookie.setMaxAge(0); + response.addCookie(authCookie); + + Cookie connectedCookie = new Cookie(COOKIE_POLLEN_CONNECTED, ""); + connectedCookie.setPath("/"); + connectedCookie.setMaxAge(0); + response.addCookie(connectedCookie); + + } + } - protected PollenRestApiRequestContext prepareRequestContext(HttpContext context) throws PollenInvalidSessionTokenException { + private PollenRestApiRequestContext prepareRequestContext(HttpContext context) throws PollenInvalidSessionTokenException, PollenCypherTechnicalException { Locale locale = getUserLocale(context); @@ -121,16 +168,38 @@ public class PollenRestApiRequestFilter extends WebMotionFilter { } - protected PollenSecurityContext createSecurityContext(HttpContext context, - PollenRestApiApplicationContext applicationContext, - PollenRestApiRequestContext requestContext) throws PollenInvalidSessionTokenException { + private PollenSecurityContext createSecurityContext(HttpContext context, + PollenRestApiApplicationContext applicationContext, + PollenRestApiRequestContext requestContext) throws PollenInvalidSessionTokenException, PollenCypherTechnicalException { SecurityService securityService = requestContext.getSecurityService(); // --- get session token (from request parameters) --- // String sessionTokenHeader = context.getHeader(REQUEST_HEADER_SESSION_TOKEN); - SessionToken sessionToken = securityService.getSessionTokenByToken(sessionTokenHeader); + if (StringUtils.isEmpty(sessionTokenHeader)) { + + // --- get session token (from request cookies) --- // + CookieManager.CookieEntity cookieEntity = context.getCookieManager().get(COOKIE_POLLEN_AUTH); + if (cookieEntity != null) { + + if (log.isDebugEnabled()) { + log.debug("Found pollen-auth cookie:: " + cookieEntity.getValue()); + } + sessionTokenHeader = securityService.decrypt(cookieEntity.getValue()); + } + + } + + SessionToken sessionToken = null; + try { + sessionToken = securityService.getSessionTokenByToken(sessionTokenHeader); + } catch (PollenInvalidSessionTokenException e) { + // session token is not valid + if (log.isErrorEnabled()) { + log.error("Found invalid session token, won't use it: " + sessionTokenHeader, e); + } + } // --- get mainPrincipal (from request parameters) --- // Map<String, String[]> parameters = context.getParameters(); @@ -144,7 +213,7 @@ public class PollenRestApiRequestFilter extends WebMotionFilter { } - protected Locale getUserLocale(HttpContext context) { + private Locale getUserLocale(HttpContext context) { String language = context.getHeader(HttpContext.HEADER_LANGUAGE); if (log.isDebugEnabled()) { diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index a2909e7..474b408 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -21,11 +21,24 @@ package org.chorem.pollen.rest.api.v1; * #L% */ +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.shiro.codec.Base64; +import org.chorem.pollen.persistence.entity.PollenToken; +import org.chorem.pollen.persistence.entity.PollenTokenImpl; import org.chorem.pollen.persistence.entity.PollenUser; +import org.chorem.pollen.persistence.entity.SessionToken; +import org.chorem.pollen.persistence.entity.SessionTokenImpl; +import org.chorem.pollen.rest.api.PollenRestApiRequestContext; import org.chorem.pollen.services.bean.PollenEntityRef; +import org.chorem.pollen.services.service.security.DefaultPollenSecurityContext; +import org.chorem.pollen.services.service.security.MissingAuthenticationException; import org.chorem.pollen.services.service.security.PollenAuthenticationException; +import org.chorem.pollen.services.service.security.PollenInvalidSessionTokenException; import org.chorem.pollen.services.service.security.SecurityService; import org.debux.webmotion.server.WebMotionController; +import org.debux.webmotion.server.call.HttpContext; /** * TODO @@ -35,16 +48,51 @@ import org.debux.webmotion.server.WebMotionController; */ public class AuthApi extends WebMotionController { - public PollenEntityRef<PollenUser> login(SecurityService securityService, String login, String password, Boolean rememberMe) throws PollenAuthenticationException { + /** Logger */ + private static final Log log = LogFactory.getLog(AuthApi.class); + + public PollenEntityRef<PollenUser> login(HttpContext requestContext, SecurityService securityService) throws PollenAuthenticationException, MissingAuthenticationException, PollenInvalidSessionTokenException { + + String authHeader = requestContext.getHeader("Authorization"); + + if (StringUtils.startsWith(authHeader, "Basic ")) { + String s = new String(Base64.decode(StringUtils.substringAfter(authHeader, "Basic "))); + String[] lp = s.split(":"); + String login = lp[0]; + String password = lp[1]; + + if (log.isInfoEnabled()) { + log.info("login@password:: " + login + "@" + password); + } + + PollenEntityRef<PollenUser> userPollenEntityRef = securityService.login(login, password, false); + + // Inject the session token in security context + PollenRestApiRequestContext pollenRestApiRequestContext = PollenRestApiRequestContext.getRequestContext(requestContext); + + SessionToken sessionTokenByToken = securityService.getSessionTokenByToken(userPollenEntityRef.getPermission()); + pollenRestApiRequestContext.getSecurityContext().setSessionToken(sessionTokenByToken); + + return userPollenEntityRef; + } + + throw new MissingAuthenticationException(); + + } + + public PollenEntityRef<PollenUser> login2(SecurityService securityService, String login, String password, Boolean rememberMe) throws PollenAuthenticationException { return securityService.login(login, password, rememberMe); } - public void logout(SecurityService securityService) { + public void logout(HttpContext requestContext, SecurityService securityService) { securityService.logout(); + // Remove the session token from security context + PollenRestApiRequestContext.getRequestContext(requestContext).getSecurityContext().setSessionToken(null); + } public void lostPassword(SecurityService securityService, String login) { diff --git a/pollen-rest-api/src/main/resources/mapping b/pollen-rest-api/src/main/resources/mapping index 3d07c2b..7ffb99e 100644 --- a/pollen-rest-api/src/main/resources/mapping +++ b/pollen-rest-api/src/main/resources/mapping @@ -54,6 +54,7 @@ GET /v1/doc DocApi.showMapping # AuthApi POST,PUT /v1/login AuthApi.login +POST,PUT /v1/login2 AuthApi.login2 GET /v1/lostpassword/{login} AuthApi.lostPassword GET /v1/logout AuthApi.logout diff --git a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml index 4c902fc..269ec67 100644 --- a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml +++ b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml @@ -20,7 +20,7 @@ #L% --> -<web-app version="3.0" id="pollen" +<web-app version="3.0" id="pollen" metadata-complete="true" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee @@ -28,6 +28,11 @@ <display-name>Pollen REST Api</display-name> + <context-param> + <param-name>wm.skip.conventionScan</param-name> + <param-value>true</param-value> + </context-param> + <filter> <filter-name>topiaTransaction</filter-name> <filter-class> @@ -35,9 +40,37 @@ </filter-class> </filter> + <filter> + <filter-name>WebMotionServer</filter-name> + <filter-class>org.debux.webmotion.server.WebMotionServer</filter-class> + <async-supported>true</async-supported> + </filter> + <filter-mapping> <filter-name>topiaTransaction</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> + <filter-mapping> + <filter-name>WebMotionServer</filter-name> + <url-pattern>/*</url-pattern> + <dispatcher>REQUEST</dispatcher> + <dispatcher>INCLUDE</dispatcher> + <dispatcher>FORWARD</dispatcher> + <dispatcher>ERROR</dispatcher> + </filter-mapping> + + <listener> + <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class> + </listener> + + <listener> + <listener-class>org.debux.webmotion.server.WebMotionServletContextListener</listener-class> + </listener> + + <!-- Force jsessionid into cookie --> + <session-config> + <tracking-mode>COOKIE</tracking-mode> + </session-config> + </web-app> diff --git a/pollen-services/pom.xml b/pollen-services/pom.xml index dc8dddb..5255520 100644 --- a/pollen-services/pom.xml +++ b/pollen-services/pom.xml @@ -75,6 +75,11 @@ <artifactId>yamlbeans</artifactId> </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk16</artifactId> + </dependency> + <!--dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> diff --git a/pollen-services/src/main/config/PollenServices.ini b/pollen-services/src/main/config/PollenServices.ini index 3674e01..ff86426 100644 --- a/pollen-services/src/main/config/PollenServices.ini +++ b/pollen-services/src/main/config/PollenServices.ini @@ -15,6 +15,14 @@ type = file transient = true final = true +[option secret] +description = pollen.configuration.secret +key = pollen.secret +type = string +defaultValue = !secret# +transient = true +final = true + [option defaultPollType] description = pollen.configuration.defaultPollType key = pollen.default.pollType @@ -123,19 +131,19 @@ final = true description = pollen.configuration.uiEndPoint key = pollen.ui.host type = url -defaultValue = http://localhost:8888/index.html +defaultValue = http://localhost:8888/app [option uiUrlPollEdit] description = pollen.configuration.uiUrlPollEdit key = pollen.ui.url.poll.edit type = string -defaultValue = ${pollen.ui.host}#/poll/edit/{pollId}/{pollToken} +defaultValue = ${pollen.ui.host}#poll/edit/{pollId}/{pollToken} [option uiUrlPollVote] description = pollen.configuration.uiUrlPollVote key = pollen.ui.url.poll.vote type = url -defaultValue = ${pollen.ui.host}#/poll/vote/{pollId}/{pollToken} +defaultValue = ${pollen.ui.host}#poll/vote/{pollId}/{pollToken} [option uiUrlPollVoteEdit] description = pollen.configurqtion.uiUrlPollVoteEdit @@ -147,4 +155,4 @@ defaultValue = ${pollen.ui.url.poll.vote}/vote/{voteToken} description = pollen.configurqtion.uiUrlUserValidate key = pollen.ui.url.user.validate type = url -defaultValue = ${pollen.ui.host}#/user/{userId}/{token} +defaultValue = ${pollen.ui.host}#signcheck/{userId}/{token} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/DefaultPollenSecurityContext.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/DefaultPollenSecurityContext.java index 9baeadd..c2f80cf 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/DefaultPollenSecurityContext.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/DefaultPollenSecurityContext.java @@ -92,6 +92,7 @@ public class DefaultPollenSecurityContext implements Serializable, PollenSecurit this.subject = subject; } + @Override public void setSessionToken(SessionToken sessionToken) { this.sessionToken = sessionToken; diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/MissingAuthenticationException.java similarity index 56% copy from pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java copy to pollen-services/src/main/java/org/chorem/pollen/services/service/security/MissingAuthenticationException.java index a0b254e..1414aff 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/MissingAuthenticationException.java @@ -21,36 +21,12 @@ package org.chorem.pollen.services.service.security; * #L% */ -import org.apache.shiro.subject.Subject; -import org.chorem.pollen.persistence.entity.PollenPrincipal; -import org.chorem.pollen.persistence.entity.PollenUser; -import org.chorem.pollen.persistence.entity.SessionToken; - /** - * Created on 5/1/14. - * * @author Tony Chemit - dev@tchemit.fr * @since 2.0 */ -public interface PollenSecurityContext { - - /** - * Get an extra credential, this is needed for protected resources, for example an private poll. - * - * @return optional credential given. - */ - PollenPrincipal getMainPrincipal(); - - SessionToken getSessionToken(); - - Subject getSubject(); - - PollenUser getPollenUser(); - - boolean isConnected(); - - boolean isAdmin(); +public class MissingAuthenticationException extends Exception { - void setSubject(Subject subject); + private static final long serialVersionUID = 1L; } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenCypherTechnicalException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenCypherTechnicalException.java new file mode 100644 index 0000000..c440c6d --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenCypherTechnicalException.java @@ -0,0 +1,16 @@ +package org.chorem.pollen.services.service.security; + +/** + * Created on 15/01/17. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 2.0 + */ +public class PollenCypherTechnicalException extends Exception { + + private static final long serialVersionUID = 1L; + + public PollenCypherTechnicalException(Throwable cause) { + super(cause); + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java index a0b254e..c3744a1 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/PollenSecurityContext.java @@ -43,6 +43,8 @@ public interface PollenSecurityContext { SessionToken getSessionToken(); + void setSessionToken(SessionToken sessionToken); + Subject getSubject(); PollenUser getPollenUser(); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index 6adb3f7..b716e1a 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -31,6 +31,16 @@ import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.RijndaelEngine; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.bouncycastle.crypto.paddings.ZeroBytePadding; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; import org.chorem.pollen.persistence.entity.Choice; import org.chorem.pollen.persistence.entity.Comment; import org.chorem.pollen.persistence.entity.CommentVisibility; @@ -46,11 +56,20 @@ import org.chorem.pollen.persistence.entity.ResultVisibility; import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.persistence.entity.Vote; import org.chorem.pollen.persistence.entity.VoteVisibility; +import org.chorem.pollen.services.PollenServiceContext; import org.chorem.pollen.services.bean.PaginationParameterBean; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.service.PollenServiceSupport; import org.nuiton.topia.persistence.TopiaEntity; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.security.Security; +import java.time.Clock; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; import java.util.HashSet; @@ -69,6 +88,40 @@ public class SecurityService extends PollenServiceSupport { /** Logger. */ private static final Log log = LogFactory.getLog(SecurityService.class); + static { + Security.addProvider(new BouncyCastleProvider()); + } + + private BufferedBlockCipher cipher; + + @Override + public void setServiceContext(PollenServiceContext serviceContext) { + super.setServiceContext(serviceContext); + BlockCipher engine = new RijndaelEngine(256); + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new ZeroBytePadding()); + + } + + @Override + public void checkIsConnected() { + + PollenSecurityContext securityContext = getSecurityContext(); + if (!securityContext.isConnected()) { + throw new PollenUnauthorizedException("connected"); + } + + } + + @Override + public void checkIsAdmin() { + + PollenSecurityContext securityContext = getSecurityContext(); + if (!securityContext.isAdmin()) { + throw new PollenUnauthorizedException("administrator"); + } + + } + public PollenEntityRef<PollenUser> login(String login, String password, Boolean rememberMe) throws PollenAuthenticationException { Subject subject = getSubject(); @@ -285,47 +338,137 @@ public class SecurityService extends PollenServiceSupport { } - public void checkIsConnected() { + public boolean isPermitted(String permission) { - PollenSecurityContext securityContext = getSecurityContext(); - if (!securityContext.isConnected()) { - throw new PollenUnauthorizedException("connected"); + Subject subject = getSubject(); + + if (log.isInfoEnabled()) { + log.info("Check permission: " + permission); } + return subject.isPermitted(permission); + } - public void checkIsAdmin() { + public void checkPermission(String permission) { - PollenSecurityContext securityContext = getSecurityContext(); - if (!securityContext.isAdmin()) { - throw new PollenUnauthorizedException("administrator"); + boolean valid = isPermitted(permission); + + if (!valid) { + throw new PollenInvalidPermissionException(permission); } } - public boolean isPermitted(String permission) { + public String encrypt(String userId, String token) throws PollenCypherTechnicalException { + try { + LocalDateTime date = LocalDateTime.now(Clock.systemUTC()); + date = date.plusDays(1); + long expired = date.toEpochSecond(ZoneOffset.UTC); - Subject subject = getSubject(); + String secret = getPollenServiceConfig().getSecret(); + String key = hashSha1(userId + expired, secret); + String encrytedValue = encrypt0(token, key); + String verifKey = hashSha1(userId + expired + token, key); - if (log.isInfoEnabled()) { - log.info("Check permission: " + permission); + return userId + "|" + expired + "|" + encrytedValue + "|" + verifKey; + + } catch (Exception e) { + throw new PollenCypherTechnicalException(e); } + } - return subject.isPermitted(permission); + public String decrypt(String encrytedValue) throws PollenCypherTechnicalException { + try { + if (encrytedValue == null) { + return null; + } + + String[] split = encrytedValue.split("\\|"); + if (split.length < 4) { + return null; + } + + LocalDateTime date = LocalDateTime.now(Clock.systemUTC()); + long now = date.toEpochSecond(ZoneOffset.UTC); + + long expired = Long.parseLong(split[1]); + if (expired < now) { + return null; + } + + String verifKey = split[3]; + String userId = split[0]; + String token = split[2]; + + String secret = getPollenServiceConfig().getSecret(); + String key = hashSha1(userId + expired, secret); + String decryptedValue = decrypt0(token, key); + String valueVerifKey = hashSha1(userId + expired + decryptedValue, key); + + if (!verifKey.equals(valueVerifKey)) { + return null; + } + return decryptedValue; + + } catch (Exception e) { + throw new PollenCypherTechnicalException(e); + } } - public void checkPermission(String permission) { + private String encrypt0(String value, String key) throws InvalidCipherTextException { - boolean valid = isPermitted(permission); + byte[] keyBytes = key.getBytes(); + cipher.init(true, new KeyParameter(keyBytes)); - if (!valid) { - throw new PollenInvalidPermissionException(permission); + byte[] input = value.getBytes(); + byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; + + int cipherLength = cipher.processBytes(input, 0, input.length, cipherText, 0); + cipher.doFinal(cipherText, cipherLength); + + return new String(Base64.encode(cipherText)); + } + + private String decrypt0(String value, String key) throws InvalidCipherTextException { + + byte[] keyBytes = key.getBytes(); + cipher.init(false, new KeyParameter(keyBytes)); + + byte[] output = Base64.decode(value.getBytes()); + byte[] cipherText = new byte[cipher.getOutputSize(output.length)]; + + int cipherLength = cipher.processBytes(output, 0, output.length, cipherText, 0); + int outputLength = cipher.doFinal(cipherText, cipherLength); + outputLength += cipherLength; + + byte[] resultBytes = cipherText; + if (outputLength != output.length) { + resultBytes = new byte[outputLength]; + System.arraycopy(cipherText, 0, resultBytes, 0, outputLength); } + return new String(resultBytes); + } + + private String hashSha1(String value, String key) throws Exception { + + byte[] keyBytes = key.getBytes(); + SecretKey secretKey = new SecretKeySpec(keyBytes, "HMac-SHA1"); + + Mac mac = Mac.getInstance("HMac-SHA1", "BC"); + mac.init(secretKey); + mac.reset(); + + byte[] input = value.getBytes(); + mac.update(input, 0, input.length); + byte[] out = mac.doFinal(); + + return new String(Base64.encode(out)); } - protected Subject getSubject() { + private Subject getSubject() { PollenSecurityContext securityContext = getSecurityContext(); Preconditions.checkNotNull(securityContext); @@ -348,11 +491,10 @@ public class SecurityService extends PollenServiceSupport { principalCollection.addAll(permissions, PollenSecurityRealm.REALM_NAME); } - subject = new Subject. - Builder(). - authenticated(securityContext.isConnected()). - principals(principalCollection). - buildSubject(); + subject = new Subject.Builder() + .authenticated(securityContext.isConnected()) + .principals(principalCollection) + .buildSubject(); securityContext.setSubject(subject); } @@ -361,7 +503,7 @@ public class SecurityService extends PollenServiceSupport { } - protected Set<String> generatePermissions(PollenSecurityContext securityContext) { + private Set<String> generatePermissions(PollenSecurityContext securityContext) { boolean userIsAdmin = securityContext.isAdmin(); @@ -497,7 +639,7 @@ public class SecurityService extends PollenServiceSupport { } - protected void generatePollPublicPermission(Set<String> permissions, Poll poll) { + private void generatePollPublicPermission(Set<String> permissions, Poll poll) { permissions.add(createSubjectPermission(PermissionVerb.readPoll, poll)); permissions.add(createSubjectPermission(PermissionVerb.addComment, poll)); permissions.add(createSubjectPermission(PermissionVerb.addVote, poll)); @@ -581,7 +723,7 @@ public class SecurityService extends PollenServiceSupport { } } - protected PrincipalByType resolvePrincipals(Set<PollenPrincipal> principals) { + private PrincipalByType resolvePrincipals(Set<PollenPrincipal> principals) { PrincipalByType principalByType = new PrincipalByType(); for (PollenPrincipal principal : principals) { @@ -605,7 +747,7 @@ public class SecurityService extends PollenServiceSupport { } - protected void resolvePrincipal(PrincipalByType principalByType, PollenPrincipal principal) { + private void resolvePrincipal(PrincipalByType principalByType, PollenPrincipal principal) { // try a poll Poll poll = getPollDao().forCreatorEquals(principal).findUniqueOrNull(); @@ -639,19 +781,19 @@ public class SecurityService extends PollenServiceSupport { } - protected String createSubjectPermission(String people, PermissionVerb verb, TopiaEntity entity) { + private String createSubjectPermission(String people, PermissionVerb verb, TopiaEntity entity) { return people + ":" + verb.name() + ":" + entity.getTopiaId(); } - protected String createSubjectPermission(PermissionVerb verb, TopiaEntity entity) { + private String createSubjectPermission(PermissionVerb verb, TopiaEntity entity) { return createSubjectPermission("*", verb, entity); } - protected String createWildcardSubjectPermission(TopiaEntity entity) { + private String createWildcardSubjectPermission(TopiaEntity entity) { return "*:*:" + entity.getTopiaId(); diff --git a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties index 7d0b986..a3475c4 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties @@ -17,6 +17,7 @@ pollen.configuration.defaultVoteCountingType=Default vote counting type used whe pollen.configuration.defaultVoteVisibility=Default vote visiblity pollen.configuration.devMode=Dev mode pollen.configuration.logConfigurationFile=Path to log configuration file +pollen.configuration.secret= pollen.configuration.sessionTimeoutDelay=Inactivity delay before invalidate the session of a user (in seconds) pollen.configuration.smptHost=Smtp Host pollen.configuration.smtpFrom=Smtp From diff --git a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties index f3d3d62..4366d77 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties @@ -17,6 +17,7 @@ pollen.configuration.defaultVoteCountingType=Type de dépouillement par défaut pollen.configuration.defaultVoteVisibility=Visibilité des votes par défaut pollen.configuration.devMode=Mode développement pollen.configuration.logConfigurationFile=Chemin vers le fichier de configuration des logs +pollen.configuration.secret= pollen.configuration.sessionTimeoutDelay=Temps autorisé d'inactivité avant d'invalider une session utilisateur (en secondes) pollen.configuration.smptHost=Hôye smtp pollen.configuration.smtpFrom=Expéditeur diff --git a/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java b/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java index d270687..1a7d57d 100644 --- a/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java +++ b/pollen-services/src/test/java/org/chorem/pollen/services/service/PollenUIUrlRenderServiceTest.java @@ -54,11 +54,11 @@ public class PollenUIUrlRenderServiceTest extends AbstractPollenServiceTest { url = service.getPollEditUrl("PollId", null); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/edit/PollId", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/edit/PollId", url); url = service.getPollEditUrl("PollId", "Token"); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/edit/PollId/Token", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/edit/PollId/Token", url); } @Test @@ -67,11 +67,11 @@ public class PollenUIUrlRenderServiceTest extends AbstractPollenServiceTest { url = service.getPollVoteUrl("PollId", null); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/vote/PollId", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/vote/PollId", url); url = service.getPollVoteUrl("PollId", "Token"); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/vote/PollId/Token", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/vote/PollId/Token", url); } @Test @@ -80,11 +80,11 @@ public class PollenUIUrlRenderServiceTest extends AbstractPollenServiceTest { url = service.getPollVoteEditUrl("PollId", null, "VoteToken"); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/vote/PollId/vote/VoteToken", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/vote/PollId/vote/VoteToken", url); url = service.getPollVoteEditUrl("PollId", "Token", "VoteToken"); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/poll/vote/PollId/Token/vote/VoteToken", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#poll/vote/PollId/Token/vote/VoteToken", url); } @Test @@ -94,7 +94,7 @@ public class PollenUIUrlRenderServiceTest extends AbstractPollenServiceTest { url = service.getUserValidateUrl("UserId", "Token"); Assert.assertNotNull(url); - Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#/user/UserId/Token", url); + Assert.assertEquals(serviceContext.getPollenServicesConfig().getUiEndPoint() + "#signcheck/UserId/Token", url); } } diff --git a/pollen-ui-riot-js/src/main/web/index.js b/pollen-ui-riot-js/src/main/web/index.js index d25dda0..a432beb 100644 --- a/pollen-ui-riot-js/src/main/web/index.js +++ b/pollen-ui-riot-js/src/main/web/index.js @@ -1,9 +1,4 @@ -let i18n = require("./js/I18nHelper"); -i18n.bundles = require("./i18n.json"); -riot.mixin(i18n); - -let session = require("./js/Session"); -session.configuration = require("./conf.json"); +riot.mixin(require("./js/I18nHelper")); require("./tag/Pollen.tag"); riot.mount("*"); diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 0efdabb..c2444c4 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -6,14 +6,15 @@ let FetchService = require("./FetchService"); class AuthService extends FetchService { signIn(login, password) { - return this.form("/v1/login", {login: login, password: password}) - .then((auth) => { - if (!auth) { - return Promise.reject(false); - } - session.signIn(auth, this); - return true; - }); + return this.fetch("/v1/login","POST", { + Authorization: "Basic " + btoa(login + ":" + password) + }, null).then((auth) => { + if (!auth) { + return Promise.reject(false); + } + session.signIn(auth, this); + return true; + }); } signUp(user) { diff --git a/pollen-ui-riot-js/src/main/web/js/FetchService.js b/pollen-ui-riot-js/src/main/web/js/FetchService.js index 41d36e4..bb285bf 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -9,13 +9,6 @@ class FetchService { headers["Content-Type"] = "application/json"; } - if (session.isConnected()) { - console.info("CONNNNNNECTED!!!") - - headers["X-Pollen-Session-Token"] = session.auth.permission; - } else { - console.info("NONONONOONONONON CONNNNNNECTED!!!") - } return fetch( session.configuration.endPoint + url, { headers, diff --git a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js index 6d3143f..d91991b 100644 --- a/pollen-ui-riot-js/src/main/web/js/I18nHelper.js +++ b/pollen-ui-riot-js/src/main/web/js/I18nHelper.js @@ -1,5 +1,9 @@ module.exports = { + init() { + this.bundles = require("../i18n.json"); + }, + installBundle(locale, value, emitter) { this.generateBundle(locale, value); emitter.onLocaleChanged((locale) => { diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index 2959f13..2b25621 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -4,12 +4,10 @@ let emitter = require("./EmitterService"); class Session { constructor() { - // pour contenir les informations de connexion - this.auth = null; // pour contenir la locale à utiliser this.locale = null; // pour contenir la configuration - this.configuration = null; + this.configuration = require('../conf.json'); // pour contenir l'utillisateur connecté this.user = null; @@ -25,12 +23,10 @@ class Session { } isConnected() { - return !!this.auth; - // return document.cookie.indexOf("pollen-connected=true") !== -1; + return document.cookie.indexOf("pollen-connected=true") !== -1; } signIn(auth, userService) { - this.auth = auth; console.info("SignIn::"); console.info(auth); userService.userPromise(auth).then((user) => { @@ -49,7 +45,6 @@ class Session { } signOut() { - delete this.auth; delete this.user; } diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag index 8460923..c1a0863 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag @@ -46,7 +46,7 @@ require("./popup/NewPassword.tag"); route(this.opts.link || "/"); }) .catch((code) => { - this.message = this.t("error_signin"); + this.message = this.__.error_signin; this.update(); }); }; diff --git a/pom.xml b/pom.xml index a6bf0a4..fb29f64 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ <topiaVersion>3.2</topiaVersion> <nuitonWebVersion>1.19-SNAPSHOT</nuitonWebVersion> - <nuitonUtilsVersion>3.0-rc-16</nuitonUtilsVersion> + <nuitonUtilsVersion>3.0-rc-17</nuitonUtilsVersion> <nuitonConfigVersion>3.1.1</nuitonConfigVersion> <nuitonCsvVersion>3.0-alpha-3</nuitonCsvVersion> <nuitonValidatorVersion>3.0.1</nuitonValidatorVersion> @@ -290,7 +290,7 @@ <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> - <version>20.0</version> + <version>21.0</version> </dependency> <!-- persistence module dependencies --> @@ -571,6 +571,13 @@ <scope>provided</scope> </dependency> + + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk16</artifactId> + <version>1.46</version> + </dependency> + <!--dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> @@ -644,7 +651,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>2.5.3</version> + <version>2.6.2</version> <scope>test</scope> </dependency> <dependency> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.
participants (1)
-
chorem.org scm