playbook_ui 11.12.1.pre.alpha.charts1 → 11.12.1.pre.alpha.passphrase1
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/index.js +1 -0
- data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.jsx +111 -0
- data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.jsx +151 -0
- data/app/pb_kits/playbook/pb_circle_chart/circle_chart.html.erb +21 -9
- data/app/pb_kits/playbook/pb_circle_chart/circle_chart.rb +47 -7
- data/app/pb_kits/playbook/pb_dashboard/{pbChartsDarkTheme.ts → pbChartsDarkTheme.js} +21 -6
- data/app/pb_kits/playbook/pb_dashboard/{pbChartsLightTheme.ts → pbChartsLightTheme.js} +21 -6
- data/app/pb_kits/playbook/pb_gauge/_gauge.jsx +112 -0
- data/app/pb_kits/playbook/pb_gauge/_gauge.scss +0 -4
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.html.erb +1 -1
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.jsx +8 -8
- data/app/pb_kits/playbook/pb_gauge/gauge.html.erb +11 -1
- data/app/pb_kits/playbook/pb_gauge/gauge.rb +8 -3
- data/app/pb_kits/playbook/pb_line_graph/_line_graph.jsx +113 -0
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.jsx +56 -97
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_breached.html.erb +145 -1
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_breached.jsx +127 -3
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_breached.md +11 -2
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_common.html.erb +136 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_common.jsx +90 -8
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_common.md +5 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_confirmation.html.erb +51 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_confirmation.jsx +39 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.html.erb +0 -2
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.jsx +6 -20
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.html.erb +2 -2
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.jsx +1 -1
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.html.erb +318 -5
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.jsx +134 -48
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.md +11 -5
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.html.erb +123 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.jsx +96 -20
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.md +6 -2
- data/app/pb_kits/playbook/pb_passphrase/docs/example.yml +4 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.html.erb +1 -1
- data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +5 -9
- data/app/pb_kits/playbook/pb_passphrase/passphrase.test.jsx +0 -47
- data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.jsx +79 -0
- data/app/pb_kits/playbook/pb_treemap_chart/docs/_treemap_chart_tooltip.jsx +1 -1
- data/app/pb_kits/playbook/playbook-rails-react-bindings.js +0 -4
- data/app/pb_kits/playbook/playbook-rails.js +4 -0
- data/app/pb_kits/playbook/plugins/pb_chart.js +322 -0
- data/lib/playbook/version.rb +1 -1
- metadata +15 -16
- data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +0 -145
- data/app/pb_kits/playbook/pb_circle_chart/ChartsTypes.ts +0 -2
- data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.tsx +0 -216
- data/app/pb_kits/playbook/pb_dashboard/pbChartsColorsHelper.ts +0 -16
- data/app/pb_kits/playbook/pb_dashboard/themeTypes.ts +0 -16
- data/app/pb_kits/playbook/pb_gauge/_gauge.tsx +0 -213
- data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +0 -148
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.md +0 -1
- data/app/pb_kits/playbook/pb_passphrase/passwordStrength.js +0 -55
- data/app/pb_kits/playbook/pb_passphrase/useHaveIBeenPwned.js +0 -52
- data/app/pb_kits/playbook/pb_passphrase/useZxcvbn.js +0 -58
- data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +0 -111
@@ -1,3 +1,12 @@
|
|
1
|
-
Use
|
1
|
+
Use <a href='https://haveibeenpwned.com/Passwords'>HaveIBeenPwned's</a> API to check for breached passwords.
|
2
|
+
|
3
|
+
As the passphrase is typed, it is checked against more than half a billion breached passwords, to help ensure its not compromised.
|
2
4
|
Should it fail, the feedback will express the passphrase is too common, prompting the user to change.
|
3
|
-
|
5
|
+
|
6
|
+
This uses their k-Anonymity model, so only the first 5 characters of a hashed copy of the passphrase are sent.
|
7
|
+
|
8
|
+
<div class="pb_pill_kit_warning"><div class="pb_title_kit_size_4 pb_pill_text">Disclaimer</div></div>
|
9
|
+
|
10
|
+
This example depends on the `zxcvbn` library and `haveibeenpwned` API.
|
11
|
+
|
12
|
+
You can use any library to achieve the same result, this example only intends to show how to add more features to the `Passphrase` kit.
|
@@ -0,0 +1,136 @@
|
|
1
|
+
<%= pb_rails("body", props: {
|
2
|
+
margin_bottom: "md",
|
3
|
+
id: "body_common"
|
4
|
+
}) %>
|
5
|
+
|
6
|
+
<%= pb_rails("passphrase", props: { label: "Passphrase", classname: "passphrase_common" }) %>
|
7
|
+
|
8
|
+
<%= pb_rails("progress_simple", props: { percent: 0, id: "bar_common" }) %>
|
9
|
+
|
10
|
+
<%= pb_rails("caption", props: { size: 'xs', text: "hello", id: "caption_common" }) %>
|
11
|
+
|
12
|
+
|
13
|
+
<%= javascript_tag do %>
|
14
|
+
window.addEventListener("DOMContentLoaded", () => {
|
15
|
+
|
16
|
+
const commonText = document.querySelector("#body_common")
|
17
|
+
|
18
|
+
// variables for the kits you are targeting
|
19
|
+
const passphrase = document.querySelector(".passphrase_common").querySelector("input")
|
20
|
+
const barVariant = document.getElementById("bar_common")
|
21
|
+
const barPercent = document.getElementById("bar_common").querySelector("div")
|
22
|
+
const caption = document.getElementById("caption_common")
|
23
|
+
|
24
|
+
// hide the bar and captions
|
25
|
+
barVariant.style.display = 'none';
|
26
|
+
barPercent.style.display = 'none';
|
27
|
+
caption.style.display = 'none';
|
28
|
+
|
29
|
+
|
30
|
+
const handleStrengthCalculation = (settings) => {
|
31
|
+
const {
|
32
|
+
passphrase = "",
|
33
|
+
common = false,
|
34
|
+
isPwned = false,
|
35
|
+
averageThreshold = 2,
|
36
|
+
minLength = 12,
|
37
|
+
strongThreshold = 3,
|
38
|
+
} = settings
|
39
|
+
|
40
|
+
const resultByScore = {
|
41
|
+
0: {
|
42
|
+
variant: 'negative',
|
43
|
+
label: '',
|
44
|
+
percent: 0,
|
45
|
+
},
|
46
|
+
1: {
|
47
|
+
variant: 'negative',
|
48
|
+
label: 'This passphrase is too common',
|
49
|
+
percent: 25,
|
50
|
+
},
|
51
|
+
2: {
|
52
|
+
variant: 'negative',
|
53
|
+
label: 'Too weak',
|
54
|
+
percent: 25,
|
55
|
+
},
|
56
|
+
3: {
|
57
|
+
variant: 'warning',
|
58
|
+
label: 'Almost there, keep going!',
|
59
|
+
percent: 50,
|
60
|
+
},
|
61
|
+
4: {
|
62
|
+
variant: 'positive',
|
63
|
+
label: 'Success! Strong passphrase',
|
64
|
+
percent: 100,
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
const { score } = zxcvbn(passphrase);
|
69
|
+
|
70
|
+
const noPassphrase = passphrase.length <= 0
|
71
|
+
const commonPassphrase = common || isPwned
|
72
|
+
const weakPassphrase = passphrase.length < minLength || score < averageThreshold
|
73
|
+
const averagePassphrase = score < strongThreshold
|
74
|
+
const strongPassphrase = score >= strongThreshold
|
75
|
+
|
76
|
+
if (noPassphrase) {
|
77
|
+
return {...resultByScore[0], score}
|
78
|
+
} else if (commonPassphrase) {
|
79
|
+
return {...resultByScore[1], score}
|
80
|
+
} else if (weakPassphrase) {
|
81
|
+
return {...resultByScore[2], score}
|
82
|
+
} else if (averagePassphrase){
|
83
|
+
return {...resultByScore[3], score}
|
84
|
+
} else if (strongPassphrase) {
|
85
|
+
return {...resultByScore[4], score}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// array that holds the common passwords you wish to target
|
90
|
+
const COMMON_PASSPHRASES = ['passphrase', 'apple', 'password', 'p@55w0rd']
|
91
|
+
|
92
|
+
commonText.textContent = `Try typing any of the following: ${COMMON_PASSPHRASES.join(', ')}`
|
93
|
+
|
94
|
+
// function that checks if the user password is in the common password list
|
95
|
+
const isCommon = (passphrase) => {
|
96
|
+
if (COMMON_PASSPHRASES.includes(passphrase))
|
97
|
+
return true
|
98
|
+
return false
|
99
|
+
}
|
100
|
+
|
101
|
+
// event listeners attached to the input field
|
102
|
+
passphrase.addEventListener('input', (e) => {
|
103
|
+
const passphrase = e.target.value;
|
104
|
+
|
105
|
+
// pass in passphrase to the handleStrengthCalculation and set that equal to result variable
|
106
|
+
const result = handleStrengthCalculation({ passphrase: passphrase, common: isCommon(passphrase) })
|
107
|
+
|
108
|
+
// conditional statment to show or hide progress_simple bar and caption if user has entered a password
|
109
|
+
if (passphrase) {
|
110
|
+
barVariant.style.display = 'block';
|
111
|
+
|
112
|
+
barPercent.style.display = 'block';
|
113
|
+
|
114
|
+
caption.style.display = 'block';
|
115
|
+
} else {
|
116
|
+
barVariant.style.display = 'none';
|
117
|
+
|
118
|
+
barPercent.style.display = 'none';
|
119
|
+
|
120
|
+
caption.style.display = 'none';
|
121
|
+
}
|
122
|
+
|
123
|
+
// set the width of the progress_simple kit
|
124
|
+
barPercent.style.width = result.percent.toString()+ "%"
|
125
|
+
|
126
|
+
|
127
|
+
// set the variant of the progress_simple kit
|
128
|
+
barVariant.setAttribute("class", "pb_progress_simple_kit_"+ result.variant +"_left");
|
129
|
+
|
130
|
+
|
131
|
+
// set the text of the caption kit
|
132
|
+
caption.textContent = result.label
|
133
|
+
});
|
134
|
+
|
135
|
+
})
|
136
|
+
<% end %>
|
@@ -1,32 +1,114 @@
|
|
1
|
-
import React, { useState } from 'react'
|
1
|
+
import React, { useState, useEffect } from 'react'
|
2
2
|
|
3
|
-
import Passphrase from '
|
4
|
-
import
|
3
|
+
import {Body, Caption, Passphrase, ProgressSimple} from '../..'
|
4
|
+
import zxcvbn from 'zxcvbn'
|
5
5
|
|
6
6
|
const PassphraseCommon = (props) => {
|
7
7
|
const [input, setInput] = useState('')
|
8
|
-
|
8
|
+
const [checkStrength, setCheckStrength] = useState({
|
9
|
+
label: '',
|
10
|
+
percent: 0,
|
11
|
+
score: 0,
|
12
|
+
variant: ''
|
13
|
+
})
|
9
14
|
const handleChange = (e) => setInput(e.target.value)
|
10
15
|
|
16
|
+
const handleStrengthCalculation = (settings) => {
|
17
|
+
const {
|
18
|
+
passphrase = "",
|
19
|
+
common = false,
|
20
|
+
isPwned = false,
|
21
|
+
averageThreshold = 2,
|
22
|
+
minLength = 12,
|
23
|
+
strongThreshold = 3,
|
24
|
+
} = settings
|
25
|
+
|
26
|
+
const resultByScore = {
|
27
|
+
0: {
|
28
|
+
variant: 'negative',
|
29
|
+
label: '',
|
30
|
+
percent: 0,
|
31
|
+
},
|
32
|
+
1: {
|
33
|
+
variant: 'negative',
|
34
|
+
label: 'This passphrase is too common',
|
35
|
+
percent: 25,
|
36
|
+
},
|
37
|
+
2: {
|
38
|
+
variant: 'negative',
|
39
|
+
label: 'Too weak',
|
40
|
+
percent: 25,
|
41
|
+
},
|
42
|
+
3: {
|
43
|
+
variant: 'warning',
|
44
|
+
label: 'Almost there, keep going!',
|
45
|
+
percent: 50,
|
46
|
+
},
|
47
|
+
4: {
|
48
|
+
variant: 'positive',
|
49
|
+
label: 'Success! Strong passphrase',
|
50
|
+
percent: 100,
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
const { score } = zxcvbn(passphrase);
|
55
|
+
|
56
|
+
const noPassphrase = passphrase.length <= 0
|
57
|
+
const commonPassphrase = common || isPwned
|
58
|
+
const weakPassphrase = passphrase.length < minLength || score < averageThreshold
|
59
|
+
const averagePassphrase = score < strongThreshold
|
60
|
+
const strongPassphrase = score >= strongThreshold
|
61
|
+
|
62
|
+
if (noPassphrase) {
|
63
|
+
return {...resultByScore[0], score}
|
64
|
+
} else if (commonPassphrase) {
|
65
|
+
return {...resultByScore[1], score}
|
66
|
+
} else if (weakPassphrase) {
|
67
|
+
return {...resultByScore[2], score}
|
68
|
+
} else if (averagePassphrase){
|
69
|
+
return {...resultByScore[3], score}
|
70
|
+
} else if (strongPassphrase) {
|
71
|
+
return {...resultByScore[4], score}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
11
75
|
const COMMON_PASSPHRASES = ['passphrase', 'apple', 'password', 'p@55w0rd']
|
12
76
|
|
13
|
-
const
|
77
|
+
const isCommon = (passphrase) => {
|
14
78
|
if (COMMON_PASSPHRASES.includes(passphrase))
|
15
79
|
return true
|
16
80
|
return false
|
17
81
|
}
|
18
82
|
|
83
|
+
useEffect(() => {
|
84
|
+
const result = handleStrengthCalculation({ passphrase: input, common: isCommon(input) });
|
85
|
+
setCheckStrength({ ...result })
|
86
|
+
}, [input])
|
87
|
+
|
88
|
+
|
19
89
|
return (
|
20
90
|
<>
|
21
91
|
<div>
|
22
|
-
<Body
|
23
|
-
|
92
|
+
<Body
|
93
|
+
marginBottom='md'
|
94
|
+
text={`Try typing any of the following: ${COMMON_PASSPHRASES.join(', ')}`} />
|
24
95
|
<Passphrase
|
25
|
-
common={commonCheck(input)}
|
26
96
|
onChange={handleChange}
|
27
97
|
value={input}
|
28
98
|
{...props}
|
29
99
|
/>
|
100
|
+
{input.length > 0 && (
|
101
|
+
<>
|
102
|
+
<ProgressSimple
|
103
|
+
className={input.length === 0 ? "progress-empty-input" : null}
|
104
|
+
percent={checkStrength.percent}
|
105
|
+
variant={checkStrength.variant}
|
106
|
+
/>
|
107
|
+
<Caption size='xs'
|
108
|
+
text={checkStrength.label}
|
109
|
+
/>
|
110
|
+
</>
|
111
|
+
)}
|
30
112
|
</div>
|
31
113
|
</>
|
32
114
|
)
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<div class="pb_pill_kit_warning"><div class="pb_title_kit_size_4 pb_pill_text">Disclaimer</div></div>
|
2
|
+
|
3
|
+
This example depends on the `zxcvbn` library.
|
4
|
+
|
5
|
+
You can use any library to achieve the same result, this example only intends to show how to add more features to the `Passphrase` kit.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%= pb_rails("passphrase", props: { classname: "pass_input_1" }) %>
|
2
|
+
|
3
|
+
<%= pb_rails("passphrase", props: { confirmation: true, classname: "pass_input_2"}) %>
|
4
|
+
|
5
|
+
<div id="match"> </div>
|
6
|
+
|
7
|
+
<%= javascript_tag do %>
|
8
|
+
window.addEventListener("DOMContentLoaded", () => {
|
9
|
+
|
10
|
+
const useState = (defaultValue) => {
|
11
|
+
let value = defaultValue;
|
12
|
+
const getValue = () => value
|
13
|
+
const setValue = (newValue) => {
|
14
|
+
return value = newValue
|
15
|
+
}
|
16
|
+
return [getValue, setValue];
|
17
|
+
}
|
18
|
+
|
19
|
+
const [input, setInput] = useState('')
|
20
|
+
const [confirmationInput, setConfirmationInput] = useState('')
|
21
|
+
|
22
|
+
const match = document.querySelector("#match")
|
23
|
+
|
24
|
+
const input1 = document.querySelector(".pass_input_1").querySelector("input")
|
25
|
+
const input2 = document.querySelector(".pass_input_2").querySelector("input")
|
26
|
+
|
27
|
+
input1.addEventListener('input', (e) => {
|
28
|
+
setInput(e.target.value)
|
29
|
+
setMatchText()
|
30
|
+
});
|
31
|
+
|
32
|
+
input2.addEventListener('input', (e) => {
|
33
|
+
setConfirmationInput(e.target.value)
|
34
|
+
setMatchText()
|
35
|
+
});
|
36
|
+
|
37
|
+
const setMatchText = () => {
|
38
|
+
|
39
|
+
if (input() && confirmationInput()) {
|
40
|
+
if (input() === confirmationInput()) {
|
41
|
+
match.textContent = "They match!"
|
42
|
+
} else {
|
43
|
+
match.textContent = "They don't match!"
|
44
|
+
}
|
45
|
+
} else {
|
46
|
+
match.textContent = ""
|
47
|
+
}
|
48
|
+
|
49
|
+
}
|
50
|
+
})
|
51
|
+
<% end %>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
|
3
|
+
import {Body, Passphrase} from '../..'
|
4
|
+
|
5
|
+
const PassphraseConfirmation = (props) => {
|
6
|
+
const [input, setInput] = useState('')
|
7
|
+
const [confirmationInput, setConfirmationInput] = useState('')
|
8
|
+
|
9
|
+
const handleChange = (e) => setInput(e.target.value)
|
10
|
+
const handleConfirmationChange = (e) => setConfirmationInput(e.target.value)
|
11
|
+
|
12
|
+
return (
|
13
|
+
<>
|
14
|
+
<div>
|
15
|
+
<Passphrase
|
16
|
+
onChange={handleChange}
|
17
|
+
value={input}
|
18
|
+
{...props}
|
19
|
+
/>
|
20
|
+
<Passphrase
|
21
|
+
confirmation
|
22
|
+
onChange={handleConfirmationChange}
|
23
|
+
value={confirmationInput}
|
24
|
+
{...props}
|
25
|
+
/>
|
26
|
+
{input && confirmationInput && (
|
27
|
+
<Body
|
28
|
+
text={
|
29
|
+
input === confirmationInput ? "They match!" : "They don't match!"
|
30
|
+
}
|
31
|
+
{...props}
|
32
|
+
/>
|
33
|
+
)}
|
34
|
+
</div>
|
35
|
+
</>
|
36
|
+
);
|
37
|
+
}
|
38
|
+
|
39
|
+
export default PassphraseConfirmation
|
@@ -6,27 +6,13 @@ const PassphraseDefault = (props) => {
|
|
6
6
|
const [input, setInput] = useState('')
|
7
7
|
const handleChange = (e) => setInput(e.target.value)
|
8
8
|
|
9
|
-
const [confoInput, setConfoInput] = useState('')
|
10
|
-
const handleConfoChange = (e) => setConfoInput(e.target.value)
|
11
|
-
|
12
9
|
return (
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
{...props}
|
20
|
-
/>
|
21
|
-
<Passphrase
|
22
|
-
confirmation
|
23
|
-
onChange={handleConfoChange}
|
24
|
-
value={confoInput}
|
25
|
-
{...props}
|
26
|
-
/>
|
27
|
-
<span>{input === confoInput ? 'They match!' : 'They don\'t match!'}</span>
|
28
|
-
</div>
|
29
|
-
</>
|
10
|
+
<Passphrase
|
11
|
+
id="my-passphrase"
|
12
|
+
onChange={handleChange}
|
13
|
+
value={input}
|
14
|
+
{...props}
|
15
|
+
/>
|
30
16
|
)
|
31
17
|
}
|
32
18
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
id: "my-disabled-passphrase",
|
5
5
|
name: "my-disabled-field",
|
6
6
|
},
|
7
|
-
label: "
|
7
|
+
label: "Pass props directly to input kit"
|
8
8
|
}) %>
|
9
9
|
|
10
10
|
<%= pb_rails("passphrase", props: {
|
@@ -12,5 +12,5 @@
|
|
12
12
|
id: "my-custome-id",
|
13
13
|
name: "my-value-name",
|
14
14
|
},
|
15
|
-
label: "Set name
|
15
|
+
label: "Set name and ID for use in form libraries"
|
16
16
|
}) %>
|
@@ -36,7 +36,7 @@ const PassphraseInputProps = (props) => {
|
|
36
36
|
{...props}
|
37
37
|
/>
|
38
38
|
<Passphrase
|
39
|
-
inputProps={{ name: 'my-value-name', id: 'my-value-id' }}
|
39
|
+
inputProps={{ name: 'my-value-name', id: 'my-value-id-2' }}
|
40
40
|
label="Set name and ID for use in form libraries"
|
41
41
|
onChange={handleChange}
|
42
42
|
value={input}
|