codevdesign 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- import i18n from '@/plugins/i18n'
2
1
  import { useAppStore } from '@/store/appStore'
3
2
 
4
3
  class RafraichisseurToken {
@@ -8,14 +7,15 @@ class RafraichisseurToken {
8
7
  private popupAffiche = false
9
8
  private appStore: ReturnType<typeof useAppStore> | null = null
10
9
  private timerId: number | null = null
11
- private deconnexionEnCours = false // évite les popups multiples
12
10
 
13
11
  // Lance une seule fois
14
12
  public async demarrer(): Promise<void> {
15
13
  this.appStore = useAppStore()
16
14
  await this.verifierToken()
17
15
  if (this.timerId != null) return
18
- this.timerId = window.setInterval(() => { this.verifierToken() }, this.intervalleEnSecondes * 1000)
16
+ this.timerId = window.setInterval(() => {
17
+ this.verifierToken()
18
+ }, this.intervalleEnSecondes * 1000)
19
19
  }
20
20
 
21
21
  // Permet d’arrêter le timer (ex: au logout / destroy)
@@ -31,7 +31,10 @@ class RafraichisseurToken {
31
31
  const modele = this.appStore?.appModele
32
32
  if (this.popupAffiche || !modele) return
33
33
  const tokenEncode = this.lireCookie(modele.nomCookie)
34
- if (!tokenEncode) { await this.rafraichir(); return }
34
+ if (!tokenEncode) {
35
+ await this.rafraichir()
36
+ return
37
+ }
35
38
 
36
39
  let token: any
37
40
  try {
@@ -42,7 +45,8 @@ class RafraichisseurToken {
42
45
  }
43
46
 
44
47
  const exp = Number(token?.exp)
45
- if (!Number.isFinite(exp)) { // exp manquant/invalide → tente refresh
48
+ if (!Number.isFinite(exp)) {
49
+ // exp manquant/invalide → tente refresh
46
50
  await this.rafraichir()
47
51
  return
48
52
  }
@@ -63,6 +67,7 @@ class RafraichisseurToken {
63
67
  const timeout = setTimeout(() => controller.abort(), 10_000)
64
68
 
65
69
  try {
70
+ //Première tentative sans iframe, pour la majorité des cas.
66
71
  const resp = await fetch(url, {
67
72
  method: 'POST',
68
73
  credentials: 'include',
@@ -72,21 +77,22 @@ class RafraichisseurToken {
72
77
  })
73
78
 
74
79
  // redirection (souvent => login) → traiter comme non auth
80
+
75
81
  if (resp.type === 'opaqueredirect' || resp.status === 302) {
76
- this.deconnecterAzure()
82
+ this.rafraichirParIframe()
77
83
  return
78
84
  }
79
85
 
80
86
  // OK ou No Content: le cookie devrait être réécrit
81
87
  if (resp.status === 200 || resp.status === 204) {
82
88
  const jeton = this.lireCookie(modele.nomCookie)
83
- if (!jeton) this.deconnecterAzure()
89
+ if (!jeton) this.rafraichirParIframe()
84
90
  return
85
91
  }
86
92
 
87
93
  // non auth / expiré (401, 419) + IIS timeout (440)
88
94
  if (resp.status === 401 || resp.status === 419 || resp.status === 440) {
89
- this.deconnecterAzure()
95
+ this.rafraichirParIframe()
90
96
  return
91
97
  }
92
98
 
@@ -100,20 +106,32 @@ class RafraichisseurToken {
100
106
  }
101
107
  }
102
108
 
103
- private deconnecterAzure(): void {
104
- if (this.deconnexionEnCours) return
105
- this.deconnexionEnCours = true
106
- const { t } = i18n.global
107
- this.popupAffiche = true
109
+ private rafraichirParIframe() {
108
110
  if (!this.appStore) this.appStore = useAppStore()
111
+ // Pour éviter les cross référence, on créé un iframe qui appel portail et force la MAJ du jeton ou l'invalidation du jeton, si jamais l'utilisateur n'est plus connecté
112
+ // ajax vers le refresh
113
+ let iframe = document.createElement('iframe')
114
+ iframe.src = `${this.appStore.appModele!.urlPortailRafraichissement}?urlRetour=${encodeURI(window.localStorage.href)}`
115
+ iframe.id = 'idRafrToken'
116
+ iframe.style.display = 'none'
117
+ document.body.appendChild(iframe)
118
+ iframe.onload = () => {
119
+ const jetonCSQC = this.lireCookie(this.appStore!.appModele!.nomCookie)
120
+ if (jetonCSQC == null || jetonCSQC === '') {
121
+ this.estDeconnecteAzure()
122
+ }
109
123
 
110
- if (this.appStore?.appModele && confirm(t('csqc.message.token'))) {
111
- const retour = encodeURI(window.location.href)
112
- window.open(`${this.appStore.appModele.urlPortailSeConnecter}?urlRetour=${retour}`, '_self')
124
+ iframe.remove()
113
125
  }
126
+ }
127
+
128
+ private estDeconnecteAzure(): void {
129
+ //on envoie au portail, pas le choix
130
+ if (!this.appStore) this.appStore = useAppStore()
114
131
 
115
- // si l’utilisateur annule, on permet un futur prompt
116
- this.deconnexionEnCours = false
132
+ const retour = encodeURI(window.location.href)
133
+ window.open(`${this.appStore.appModele!.urlPortailSeConnecter}?urlRetour=${retour}`, '_self')
134
+ return
117
135
  }
118
136
 
119
137
  public deconnecterPortail(): void {
@@ -121,23 +139,20 @@ class RafraichisseurToken {
121
139
  const modele = this.appStore?.appModele
122
140
  if (!modele) return
123
141
 
124
- window.location.replace(
125
- `${modele.urlPortail}deconnecte?urlRetour=${encodeURIComponent(window.location.href)}`
126
- )
142
+ window.location.replace(`${modele.urlPortail}deconnecte?urlRetour=${encodeURIComponent(window.location.href)}`)
127
143
  }
128
144
 
129
- public annulerDeconnecter(): void {
130
- this.popupAffiche = false
131
- this.deconnexionEnCours = false
132
- }
133
145
 
134
146
  private lireCookie(nom: string): string | null {
135
147
  if (!document.cookie) return null
136
148
  const cookies = document.cookie.split(';').map(c => c.trim())
137
149
  for (const cookie of cookies) {
138
150
  if (cookie.startsWith(`${nom}=`)) {
139
- try { return decodeURIComponent(cookie.substring(nom.length + 1)) }
140
- catch { return cookie.substring(nom.length + 1) }
151
+ try {
152
+ return decodeURIComponent(cookie.substring(nom.length + 1))
153
+ } catch {
154
+ return cookie.substring(nom.length + 1)
155
+ }
141
156
  }
142
157
  }
143
158
  return null
@@ -150,14 +165,17 @@ class RafraichisseurToken {
150
165
  if (!base64Url) throw new Error('Invalid JWT format')
151
166
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
152
167
  const jsonPayload = decodeURIComponent(
153
- atob(base64).split('').map(c => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`).join('')
168
+ atob(base64)
169
+ .split('')
170
+ .map(c => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)
171
+ .join(''),
154
172
  )
155
173
  return JSON.parse(jsonPayload)
156
174
  }
157
175
 
158
176
  // URL refresh selon env (dev = proxy Vite ; prod = portail)
159
177
  private getRefreshUrl(): string {
160
- if (import.meta.env.MODE === "development") return '/portail-refresh'
178
+ if (import.meta.env.MODE === 'development') return '/portail-refresh'
161
179
  return this.appStore!.appModele!.urlPortailRafraichissement
162
180
  }
163
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codevdesign",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Composants Vuetify 3 pour les projets Codev",
5
5
  "files": [
6
6
  "./**/*.vue",
@@ -29,4 +29,4 @@
29
29
  "peerDependencies": {
30
30
  "vue": "^3.5.0"
31
31
  }
32
- }
32
+ }