playbook_ui 11.12.1.pre.alpha.charts1 → 11.12.1.pre.alpha.passphrase1
Sign up to get free protection for your applications and to get access to all the features.
- 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}
|