lesli_shield 1.1.4 → 1.1.5
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/assets/config/lesli_shield_manifest.js +1 -0
- data/app/assets/stylesheets/lesli_shield/application.tailwind.css +0 -0
- data/app/assets/stylesheets/lesli_shield/confirmations.css +18 -18959
- data/app/assets/stylesheets/lesli_shield/passwords.css +18 -18912
- data/app/assets/stylesheets/lesli_shield/registrations.css +0 -18227
- data/app/assets/stylesheets/lesli_shield/sessions.css +1 -18970
- data/app/assets/stylesheets/lesli_shield/sessions.tailwind.css +2 -0
- data/app/services/lesli_shield/user_registration_service.rb +45 -32
- data/app/views/devise/sessions/new.html.erb +36 -32
- data/app/views/devise/shared/_application-devise.html.erb +36 -34
- data/app/views/devise/shared/_demo.html.erb +8 -4
- data/lib/lesli_shield/version.rb +2 -2
- data/readme.md +112 -49
- metadata +3 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-content:""}}}@layer theme{:root,:host{--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-200:oklch(90.1% .058 230.902);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-sky-700:oklch(50% .134 242.749);--color-sky-800:oklch(44.3% .11 240.79);--color-sky-900:oklch(39.1% .09 240.876);--color-sky-950:oklch(29.3% .066 243.157);--color-rose-50:oklch(96.9% .015 12.422);--color-rose-200:oklch(89.2% .058 10.001);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-rose-600:oklch(58.6% .253 17.585);--color-rose-700:oklch(51.4% .222 16.935);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-slate-950:oklch(12.9% .042 264.695);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--leading-tight:1.25;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{inset-inline:0}.bottom-0{bottom:0}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-1{margin-right:var(--spacing)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.h-5{height:calc(var(--spacing) * 5)}.h-auto{height:auto}.max-h-20{max-height:calc(var(--spacing) * 20)}.min-h-screen{min-height:100vh}.w-5{width:calc(var(--spacing) * 5)}.w-auto{width:auto}.w-full{width:100%}.max-w-\[220px\]{max-width:220px}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-y-1{row-gap:var(--spacing)}.overflow-hidden{overflow:hidden}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-sky-200{border-color:var(--color-sky-200)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-white{background-color:var(--color-white)}.bg-gradient-to-t{--tw-gradient-position:to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-slate-950\/70{--tw-gradient-from:#020618b3}@supports (color:color-mix(in lab, red, red)){.from-slate-950\/70{--tw-gradient-from:color-mix(in oklab, var(--color-slate-950) 70%, transparent)}}.from-slate-950\/70{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.via-slate-900\/10{--tw-gradient-via:#0f172b1a}@supports (color:color-mix(in lab, red, red)){.via-slate-900\/10{--tw-gradient-via:color-mix(in oklab, var(--color-slate-900) 10%, transparent)}}.via-slate-900\/10{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-12{padding:calc(var(--spacing) * 12)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.break-all{word-break:break-all}.text-sky-700{color:var(--color-sky-700)}.text-sky-800{color:var(--color-sky-800)}.text-sky-950{color:var(--color-sky-950)}.text-slate-600{color:var(--color-slate-600)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:text-sky-900:hover{color:var(--color-sky-900)}}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-sky-500\/30:focus{--tw-ring-color:#00a5ef4d}@supports (color:color-mix(in lab, red, red)){.focus\:ring-sky-500\/30:focus{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 30%, transparent)}}.focus\:ring-offset-4:focus{--tw-ring-offset-width:4px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}@media (min-width:40rem){.sm\:px-10{padding-inline:calc(var(--spacing) * 10)}.sm\:pt-8{padding-top:calc(var(--spacing) * 8)}}@media (min-width:64rem){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:block{display:block}.lg\:grid{display:grid}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-16{padding-inline:calc(var(--spacing) * 16)}}}@layer components{.lesli-form-field{margin-bottom:calc(var(--spacing) * 4)}.lesli-form-label-wrapper{margin-bottom:calc(var(--spacing) * 2)}.lesli-form-label{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-slate-700);display:block}.lesli-form-field-body{min-width:0}.lesli-form-control{position:relative}.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor{border-radius:var(--radius-xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-slate-300);background-color:var(--color-white);width:100%;padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--color-slate-900);--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-outline-style:none;outline-style:none;display:block}:is(.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor)::placeholder{color:var(--color-slate-400)}@media (hover:hover){:is(.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor):hover{border-color:var(--color-slate-400)}}:is(.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor):focus{border-color:var(--color-sky-500);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:#00a5ef1a}@supports (color:color-mix(in lab, red, red)){:is(.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor):focus{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 10%, transparent)}}:is(.lesli-form-input,.lesli-form-select,.lesli-form-control textarea,.lesli-form-control trix-editor):disabled{cursor:not-allowed;background-color:var(--color-slate-100);color:var(--color-slate-500);opacity:.75}.lesli-form-input,.lesli-form-select{height:calc(var(--spacing) * 11)}.lesli-form-control textarea,.lesli-form-control trix-editor{min-height:calc(var(--spacing) * 32);resize:vertical}.lesli-form-select-wrapper{position:relative}.lesli-form-select{cursor:pointer;appearance:none;padding-right:calc(var(--spacing) * 10)}.lesli-form-select-wrapper:after{pointer-events:none;top:50%;right:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 2);width:calc(var(--spacing) * 2);--tw-translate-y:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y);border-right-style:var(--tw-border-style);border-right-width:2px;border-bottom-style:var(--tw-border-style);border-bottom-width:2px;border-color:var(--color-slate-400);--tw-content:"";content:var(--tw-content);position:absolute;rotate:45deg}.lesli-form-checkbox{height:calc(var(--spacing) * 4);width:calc(var(--spacing) * 4);cursor:pointer;border-color:var(--color-slate-300);accent-color:var(--color-sky-600);border-radius:.25rem}.lesli-form-checkbox:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:#00a5ef4d}@supports (color:color-mix(in lab, red, red)){.lesli-form-checkbox:focus{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 30%, transparent)}}.lesli-form-checkbox:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.lesli-form-checkbox:disabled{cursor:not-allowed;opacity:.5}.lesli-form-checkbox-label{cursor:pointer;align-items:center;gap:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--color-slate-600);display:inline-flex}.lesli-form-control.has-icon .lesli-form-input,.lesli-form-control.has-icon .lesli-form-select{padding-left:calc(var(--spacing) * 11)}.lesli-form-icon{pointer-events:none;top:50%;left:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y);color:var(--color-slate-400);justify-content:center;align-items:center;display:inline-flex;position:absolute}.lesli-form-icon .material-symbols-outlined{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1;line-height:1}.lesli-form-help{margin-top:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);color:var(--color-slate-500)}.lesli-form-field.is-danger .lesli-form-input,.lesli-form-field.is-danger .lesli-form-select,.lesli-form-field.is-danger textarea,.lesli-form-field.is-danger trix-editor{border-color:var(--color-rose-400)}:is(.lesli-form-field.is-danger .lesli-form-input,.lesli-form-field.is-danger .lesli-form-select,.lesli-form-field.is-danger textarea,.lesli-form-field.is-danger trix-editor):focus{border-color:var(--color-rose-500);--tw-ring-color:#ff23571a}@supports (color:color-mix(in lab, red, red)){:is(.lesli-form-field.is-danger .lesli-form-input,.lesli-form-field.is-danger .lesli-form-select,.lesli-form-field.is-danger textarea,.lesli-form-field.is-danger trix-editor):focus{--tw-ring-color:color-mix(in oklab, var(--color-rose-500) 10%, transparent)}}.lesli-form-help.is-danger{color:var(--color-rose-700)}.lesli-form-help.is-warning{color:var(--color-amber-700)}.lesli-form-help.is-success{color:var(--color-emerald-700)}.lesli-form-help.is-info{color:var(--color-sky-700)}.lesli-form-button{height:calc(var(--spacing) * 11);cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 2);border-radius:var(--radius-xl);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-width:1px;border-color:#0000;display:inline-flex}.lesli-form-button:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-outline-style:none;outline-style:none}.lesli-form-button:disabled{pointer-events:none;cursor:not-allowed;opacity:.5}.lesli-form-button.is-primary,.lesli-form-button.is-info{background-color:var(--color-sky-600);color:var(--color-white)}@media (hover:hover){:is(.lesli-form-button.is-primary,.lesli-form-button.is-info):hover{background-color:var(--color-sky-700)}}:is(.lesli-form-button.is-primary,.lesli-form-button.is-info):focus{--tw-ring-color:#00a5ef33}@supports (color:color-mix(in lab, red, red)){:is(.lesli-form-button.is-primary,.lesli-form-button.is-info):focus{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 20%, transparent)}}.lesli-form-button.is-success{background-color:var(--color-emerald-600);color:var(--color-white)}@media (hover:hover){.lesli-form-button.is-success:hover{background-color:var(--color-emerald-700)}}.lesli-form-button.is-success:focus{--tw-ring-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.lesli-form-button.is-success:focus{--tw-ring-color:color-mix(in oklab, var(--color-emerald-500) 20%, transparent)}}.lesli-form-button.is-warning{background-color:var(--color-amber-500);color:var(--color-amber-950)}@media (hover:hover){.lesli-form-button.is-warning:hover{background-color:var(--color-amber-600)}}.lesli-form-button.is-warning:focus{--tw-ring-color:#f99c0033}@supports (color:color-mix(in lab, red, red)){.lesli-form-button.is-warning:focus{--tw-ring-color:color-mix(in oklab, var(--color-amber-500) 20%, transparent)}}.lesli-form-button.is-danger{background-color:var(--color-rose-600);color:var(--color-white)}@media (hover:hover){.lesli-form-button.is-danger:hover{background-color:var(--color-rose-700)}}.lesli-form-button.is-danger:focus{--tw-ring-color:#ff235733}@supports (color:color-mix(in lab, red, red)){.lesli-form-button.is-danger:focus{--tw-ring-color:color-mix(in oklab, var(--color-rose-500) 20%, transparent)}}.lesli-form-button.is-fullwidth{width:100%}.lesli-form-button-icon{height:calc(var(--spacing) * 5);width:calc(var(--spacing) * 5);justify-content:center;align-items:center;display:inline-flex}.lesli-form-button-icon .material-symbols{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1;line-height:1}.lesli-form-fieldset{margin-bottom:calc(var(--spacing) * 6);border-radius:var(--radius-2xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-slate-200);background-color:var(--color-white);padding:calc(var(--spacing) * 6);--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.lesli-form-legend{margin-bottom:calc(var(--spacing) * 5);margin-left:calc(var(--spacing) * -1);padding-inline:var(--spacing);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-slate-800)}.lesli-form-fieldset.is-info{border-color:var(--color-sky-200);background-color:#f0f9ff66}@supports (color:color-mix(in lab, red, red)){.lesli-form-fieldset.is-info{background-color:color-mix(in oklab, var(--color-sky-50) 40%, transparent)}}.lesli-form-fieldset.is-success{border-color:var(--color-emerald-200);background-color:#ecfdf566}@supports (color:color-mix(in lab, red, red)){.lesli-form-fieldset.is-success{background-color:color-mix(in oklab, var(--color-emerald-50) 40%, transparent)}}.lesli-form-fieldset.is-warning{border-color:var(--color-amber-200);background-color:#fffbeb80}@supports (color:color-mix(in lab, red, red)){.lesli-form-fieldset.is-warning{background-color:color-mix(in oklab, var(--color-amber-50) 50%, transparent)}}.lesli-form-fieldset.is-danger{border-color:var(--color-rose-200);background-color:#fff1f266}@supports (color:color-mix(in lab, red, red)){.lesli-form-fieldset.is-danger{background-color:color-mix(in oklab, var(--color-rose-50) 40%, transparent)}}@media (min-width:768px){.lesli-form-field.is-horizontal{align-items:flex-start;gap:calc(var(--spacing) * 5);grid-template-columns:minmax(8rem,1fr) minmax(0,3fr);display:grid}.lesli-form-field.is-horizontal>.lesli-form-label-wrapper{padding-top:calc(var(--spacing) * 2.5);text-align:right;margin-bottom:0}.lesli-form-field.is-horizontal>.lesli-form-field-body{grid-column-start:2}}.links{margin-top:calc(var(--spacing) * 5);border-radius:var(--radius-xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-slate-200);background-color:var(--color-white);overflow:hidden}.links>a{align-items:center;gap:calc(var(--spacing) * 3);width:100%;padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-slate-700);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));display:flex}@media (hover:hover){.links>a:hover{background-color:var(--color-slate-50);color:var(--color-sky-700)}}.links>a:focus{--tw-outline-style:none;outline-style:none}.links>a:focus-visible{background-color:var(--color-sky-50);--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:#00a5ef4d}@supports (color:color-mix(in lab, red, red)){.links>a:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 30%, transparent)}}.links>a:focus-visible{--tw-ring-inset:inset}.links>a:not(:last-child){border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--color-slate-200)}.links .icon{height:calc(var(--spacing) * 7);width:calc(var(--spacing) * 7);flex-shrink:0;justify-content:center;align-items:center;margin-right:0;display:inline-flex}.links .icon svg{max-height:calc(var(--spacing) * 6);max-width:calc(var(--spacing) * 6);display:block}.links>a>span:not(.icon){font-family:Domine,OpenSans,sans-serif}.lesli-auth-visual{background-color:#0000;background-image:linear-gradient(#316aff66,#316aff66),url(/lesli_shield/login-background.jpg);background-position:50%;background-repeat:repeat,repeat;background-size:cover;background-attachment:scroll,scroll;background-origin:padding-box,padding-box;background-clip:border-box,border-box}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-content{syntax:"*";inherits:false;initial-value:""}
|
|
@@ -56,10 +56,44 @@ module LesliShield
|
|
|
56
56
|
|
|
57
57
|
def create_account
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
add_account() if resource.account.blank?
|
|
60
|
+
add_role() if resource.user_roles.empty?
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
# Synchronize roles for the very first time
|
|
63
|
+
resource.roles.each do |role|
|
|
64
|
+
LesliShield::RolePrivilegeService.new(nil).synchronize(role)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# update user :)
|
|
68
|
+
resource.save
|
|
69
|
+
|
|
70
|
+
# # initialize user dependencies
|
|
71
|
+
# def after_account_assignation
|
|
72
|
+
# return unless self.account
|
|
73
|
+
|
|
74
|
+
# #Courier::One::Firebase::User.sync_user(self)
|
|
75
|
+
# # Lesli::Courier.new(:lesli_calendar).from(:calendar_service, self).create({
|
|
76
|
+
# # name: "Personal Calendar",
|
|
77
|
+
# # default: true
|
|
78
|
+
# # })
|
|
79
|
+
# end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# check if instance is for multi-account
|
|
86
|
+
ALLOW_MULTI_ACCOUNT = Lesli.config.security.dig(:allow_multiaccount)
|
|
87
|
+
|
|
88
|
+
# This is necessary when user is creating a brand new account
|
|
89
|
+
# and the platform is configured to create new Lesli accounts for every user
|
|
90
|
+
# The platform use the same account when the platform is not saas but
|
|
91
|
+
# proprietary instance (only one company is using the platform)
|
|
92
|
+
# Another scenario where it is not needed to create a new account for the
|
|
93
|
+
# user is when the user is confirming the account through an invitation
|
|
94
|
+
def add_account
|
|
95
|
+
|
|
96
|
+
if ALLOW_MULTI_ACCOUNT === true
|
|
63
97
|
# create new account for the new user only if multi-account is allowed
|
|
64
98
|
account = Lesli::Account.create!({
|
|
65
99
|
user: resource, # set user as owner of his just created account
|
|
@@ -74,42 +108,21 @@ module LesliShield
|
|
|
74
108
|
|
|
75
109
|
# add user to his own account
|
|
76
110
|
resource.account = account
|
|
77
|
-
|
|
78
|
-
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def add_role
|
|
114
|
+
if ALLOW_MULTI_ACCOUNT == true
|
|
79
115
|
# add owner role to user only if multi-account is allowed
|
|
80
116
|
resource.user_roles.create({ role: account.roles.find_by(name: "owner") })
|
|
81
117
|
else
|
|
82
118
|
# Assigning default role if defined in account settings
|
|
83
119
|
# Otherwise, the default role is "limited"
|
|
84
|
-
|
|
85
|
-
default_role_id = Lesli.config.shield.dig(:default_role)
|
|
86
|
-
|
|
87
|
-
if default_role_id.present?
|
|
88
|
-
resource.roles.create({ role: account.roles.find_by(:id => default_role_id)})
|
|
89
|
-
else
|
|
90
|
-
resource.roles.create({ role: account.roles.find_by(name: "limited") })
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Synchronize roles for the very first time
|
|
95
|
-
resource.roles.each do |role|
|
|
96
|
-
LesliShield::RolePrivilegeService.new(nil).synchronize(role)
|
|
97
|
-
end
|
|
120
|
+
default_role_name = Lesli.config.shield.dig(:default_role) || "guest"
|
|
98
121
|
|
|
99
|
-
|
|
100
|
-
resource.save
|
|
101
|
-
|
|
102
|
-
# # initialize user dependencies
|
|
103
|
-
# def after_account_assignation
|
|
104
|
-
# return unless self.account
|
|
105
|
-
|
|
106
|
-
# #Courier::One::Firebase::User.sync_user(self)
|
|
107
|
-
# # Lesli::Courier.new(:lesli_calendar).from(:calendar_service, self).create({
|
|
108
|
-
# # name: "Personal Calendar",
|
|
109
|
-
# # default: true
|
|
110
|
-
# # })
|
|
111
|
-
# end
|
|
122
|
+
default_role = resource.account.roles.find_by(name: default_role_name)
|
|
112
123
|
|
|
124
|
+
resource.user_roles.create({ role: default_role })
|
|
125
|
+
end
|
|
113
126
|
end
|
|
114
127
|
end
|
|
115
128
|
end
|
|
@@ -44,59 +44,63 @@ title = I18n.t("overrides.lesli_shield.devise/sessions.view_title",
|
|
|
44
44
|
default: :"lesli_shield.devise/sessions.view_title")
|
|
45
45
|
%>
|
|
46
46
|
|
|
47
|
-
<%= render("devise/shared/application-devise", title:title) do %>
|
|
47
|
+
<%= render("devise/shared/application-devise", title: title) do %>
|
|
48
|
+
|
|
49
|
+
<% authentication_error = flash[:alert].presence || flash[:error].presence %>
|
|
48
50
|
|
|
49
51
|
<%= form_for(
|
|
50
|
-
resource,
|
|
51
|
-
as: resource_name,
|
|
52
|
+
resource,
|
|
53
|
+
as: resource_name,
|
|
52
54
|
url: user_session_path,
|
|
53
55
|
builder: LesliView::Forms::Builder,
|
|
56
|
+
html: { class: "lesli-login-form" },
|
|
54
57
|
data: { turbo: false }
|
|
55
|
-
|
|
58
|
+
) do |form| %>
|
|
56
59
|
|
|
57
60
|
<% if Lesli.config.demo %>
|
|
58
61
|
<%= render("devise/shared/demo") %>
|
|
59
62
|
<% end %>
|
|
60
63
|
|
|
61
|
-
<%= form.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
category:
|
|
65
|
-
icon: "person"
|
|
64
|
+
<%= form.field_control_email(
|
|
65
|
+
:email,
|
|
66
|
+
label: I18n.t("lesli_shield.devise/sessions.label_email", default: "Email address"),
|
|
67
|
+
category: authentication_error.present? ? :danger : nil,
|
|
68
|
+
icon: "person",
|
|
69
|
+
autofocus: true,
|
|
70
|
+
autocomplete: "email",
|
|
71
|
+
required: true,
|
|
72
|
+
placeholder: Lesli.config.company[:email]
|
|
66
73
|
) %>
|
|
67
74
|
|
|
68
|
-
<%= form.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
category:
|
|
73
|
-
icon: "key"
|
|
75
|
+
<%= form.field_control_password(
|
|
76
|
+
:password,
|
|
77
|
+
label: I18n.t("lesli_shield.devise/sessions.label_password", default: "Password"),
|
|
78
|
+
message: authentication_error,
|
|
79
|
+
category: authentication_error.present? ? :danger : nil,
|
|
80
|
+
icon: "key",
|
|
81
|
+
autocomplete: "current-password",
|
|
82
|
+
required: true,
|
|
83
|
+
placeholder: "••••••••"
|
|
74
84
|
) %>
|
|
75
85
|
|
|
76
86
|
<% if params[:r].presence %>
|
|
77
|
-
<%=
|
|
87
|
+
<%= hidden_field_tag "user[redirect]", params[:r] %>
|
|
78
88
|
<% end %>
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<%= I18n.t("lesli_shield.devise/sessions.button_log_in") %>
|
|
86
|
-
</button>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
90
|
+
<%= form.field_control_button(
|
|
91
|
+
I18n.t("lesli_shield.devise/sessions.button_log_in"),
|
|
92
|
+
{ class: "is-fullwidth" },
|
|
93
|
+
icon: "login"
|
|
94
|
+
) %>
|
|
89
95
|
|
|
90
96
|
<% if Lesli.config.security.dig(:allow_registration) %>
|
|
91
|
-
<p class="
|
|
97
|
+
<p class="mt-1 text-center text-sm text-slate-600">
|
|
92
98
|
<%= I18n.t("lesli_shield.devise/sessions.view_still_not_registered") %>
|
|
93
|
-
<%= link_to(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</p>
|
|
99
|
+
<%= link_to I18n.t("lesli_shield.devise/sessions.button_create_account"),
|
|
100
|
+
new_user_registration_path %>
|
|
101
|
+
</p>
|
|
97
102
|
<% end %>
|
|
98
|
-
|
|
99
103
|
<% end %>
|
|
100
104
|
|
|
101
|
-
<%= render("devise/shared/links", password_reset:true, magic_link:
|
|
105
|
+
<%= render("devise/shared/links", password_reset:true, magic_link:true, otp:true, login:true) %>
|
|
102
106
|
<% end %>
|
|
@@ -30,46 +30,48 @@ Building a better future, one line of code at a time.
|
|
|
30
30
|
// ·
|
|
31
31
|
%>
|
|
32
32
|
|
|
33
|
-
<% title =
|
|
34
|
-
<% back_to_login =
|
|
33
|
+
<% title = local_assigns.fetch(:title, "") %>
|
|
34
|
+
<% back_to_login = local_assigns.fetch(:back_to_login, false) %>
|
|
35
35
|
|
|
36
|
-
<main id="lesli-application" class="
|
|
37
|
-
<section class="
|
|
38
|
-
|
|
39
|
-
<div class="
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</span>
|
|
47
|
-
<span>Back to Login</span>
|
|
48
|
-
</span>
|
|
49
|
-
<% end %>
|
|
50
|
-
</div>
|
|
36
|
+
<main id="lesli-application" class="min-h-screen bg-slate-50 lg:grid lg:grid-cols-3">
|
|
37
|
+
<section class="flex min-h-screen flex-col bg-white">
|
|
38
|
+
<% if back_to_login %>
|
|
39
|
+
<div class="px-6 pt-6 sm:px-10 sm:pt-8">
|
|
40
|
+
<%= link_to new_user_session_path,
|
|
41
|
+
class: "inline-flex items-center gap-2 rounded-lg text-sm font-medium text-sky-700 transition hover:text-sky-900 focus:outline-none focus:ring-2 focus:ring-sky-500/30 focus:ring-offset-4" do %>
|
|
42
|
+
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
|
43
|
+
<path d="m12.5 15-5-5 5-5" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
|
|
44
|
+
</svg>
|
|
45
|
+
<span><%= I18n.t("actions.back_to_login", default: "Back to login") %></span>
|
|
51
46
|
<% end %>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<%# Logo container %>
|
|
55
|
-
<div class="logo has-text-centered mb-6">
|
|
56
|
-
<%= image_tag(
|
|
57
|
-
"lesli_assets/brand/app-auth.svg",
|
|
58
|
-
:class => "#{lesli_instance_code}-logo mb-2",
|
|
59
|
-
:alt => "Main logo")
|
|
60
|
-
%>
|
|
61
|
-
<h1 class="is-title is-size-3 has-text-primary">
|
|
62
|
-
<%= title %>
|
|
63
|
-
</h1>
|
|
64
|
-
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<% end %>
|
|
65
49
|
|
|
66
|
-
|
|
50
|
+
<div class="flex flex-1 items-center justify-center px-6 py-10 sm:px-10 lg:px-16">
|
|
51
|
+
<div class="w-full max-w-md">
|
|
52
|
+
<div class="mb-8 text-center">
|
|
53
|
+
<%= image_tag(
|
|
54
|
+
"lesli_assets/brand/app-auth.svg",
|
|
55
|
+
class: "#{lesli_instance_code}-logo mx-auto mb-6 h-auto max-h-20 w-auto max-w-[220px]",
|
|
56
|
+
alt: I18n.t("lesli_shield.authentication.logo_alt", default: "Application logo")
|
|
57
|
+
) %>
|
|
67
58
|
|
|
59
|
+
<% if title.present? %>
|
|
60
|
+
<h1 class="text-3xl font-semibold tracking-tight text-slate-900"><%= title %></h1>
|
|
61
|
+
<% end %>
|
|
68
62
|
</div>
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
|
|
64
|
+
<%= yield %>
|
|
71
65
|
</div>
|
|
72
66
|
</div>
|
|
73
|
-
<div class="column background is-hidden-touch"></div>
|
|
74
67
|
</section>
|
|
68
|
+
|
|
69
|
+
<aside class="lesli-auth-visual relative hidden min-h-screen overflow-hidden lg:col-span-2 lg:block" aria-hidden="true">
|
|
70
|
+
<div class="absolute inset-0 bg-gradient-to-t from-slate-950/70 via-slate-900/10 to-transparent"></div>
|
|
71
|
+
<div class="absolute inset-x-0 bottom-0 p-12 text-white">
|
|
72
|
+
<p class="max-w-lg text-3xl font-semibold leading-tight">
|
|
73
|
+
<%= I18n.t("lesli_shield.authentication.tagline", default: "A better way to manage your work.") %>
|
|
74
|
+
</p>
|
|
75
|
+
</div>
|
|
76
|
+
</aside>
|
|
75
77
|
</main>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
<fieldset class="
|
|
3
|
-
<legend>
|
|
4
|
-
<
|
|
5
|
-
|
|
2
|
+
<fieldset class="mb-8 rounded-xl border border-sky-200 bg-sky-50 px-4 pb-4 text-sm text-sky-950">
|
|
3
|
+
<legend class="px-2 font-semibold text-sky-800">Demo account</legend>
|
|
4
|
+
<dl class="mt-1 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1">
|
|
5
|
+
<dt class="font-medium">Username:</dt>
|
|
6
|
+
<dd class="break-all"><%= Lesli.config.company[:email] %></dd>
|
|
7
|
+
<dt class="font-medium">Password:</dt>
|
|
8
|
+
<dd><%= Lesli.config.security[:password] %></dd>
|
|
9
|
+
</dl>
|
|
6
10
|
</fieldset>
|
data/lib/lesli_shield/version.rb
CHANGED
data/readme.md
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<
|
|
3
|
-
|
|
2
|
+
<h1 align="center">
|
|
3
|
+
<img width="100" alt="LesliShield" src="./app/assets/images/lesli_shield/shield-logo.svg" />
|
|
4
|
+
</h1>
|
|
5
|
+
<h3 align="center">Authentication and authorization for the Lesli Framework.</h3>
|
|
4
6
|
</div>
|
|
5
7
|
|
|
6
8
|
<br />
|
|
7
|
-
<hr/>
|
|
8
9
|
|
|
9
10
|
<div align="center">
|
|
10
|
-
<a target="_blank" href="https://github.com/LesliTech/LesliShield/actions">
|
|
11
|
-
<img alt="
|
|
11
|
+
<a target="_blank" href="https://github.com/LesliTech/LesliShield/actions/workflows/lesli-ci-tests.yaml">
|
|
12
|
+
<img alt="LesliShield test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliShield/lesli-ci-tests.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
|
|
12
13
|
</a>
|
|
13
14
|
<a target="_blank" href="https://rubygems.org/gems/lesli_shield">
|
|
14
15
|
<img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_shield?style=for-the-badge&logo=ruby">
|
|
@@ -16,84 +17,148 @@
|
|
|
16
17
|
<a target="_blank" href="https://codecov.io/github/LesliTech/LesliShield">
|
|
17
18
|
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/LesliTech/LesliShield?style=for-the-badge&logo=codecov">
|
|
18
19
|
</a>
|
|
20
|
+
<a target="_blank" href="https://sonarcloud.io/project/overview?id=LesliTech_LesliShield">
|
|
21
|
+
<img alt="Sonar Quality Gate" src="https://img.shields.io/sonar/quality_gate/LesliTech_LesliShield?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarqubecloud&label=Quality">
|
|
22
|
+
</a>
|
|
19
23
|
</div>
|
|
20
24
|
|
|
21
|
-
<hr/>
|
|
22
25
|
<br />
|
|
23
26
|
|
|
24
27
|
<div align="center">
|
|
25
28
|
<img
|
|
26
29
|
style="width:100%;max-width:800px;border-radius:6px;"
|
|
27
|
-
alt="
|
|
30
|
+
alt="LesliShield security administration"
|
|
31
|
+
src="./docs/images/screenshot.png" />
|
|
28
32
|
</div>
|
|
29
33
|
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<br />
|
|
37
|
+
|
|
38
|
+
## Introduction
|
|
39
|
+
|
|
40
|
+
LesliShield is the official authentication and authorization engine for the [Lesli Framework](https://github.com/LesliTech/Lesli).
|
|
41
|
+
|
|
42
|
+
It centralizes account security, role-based access control, and user onboarding for Lesli applications.
|
|
43
|
+
|
|
30
44
|
<br />
|
|
31
|
-
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- Authentication and session management
|
|
49
|
+
- Role-based access control
|
|
50
|
+
- Permission and privilege administration
|
|
51
|
+
- Account-scoped security policies
|
|
52
|
+
- User invitations and onboarding
|
|
53
|
+
|
|
32
54
|
<br />
|
|
33
55
|
|
|
34
|
-
|
|
56
|
+
## Try LesliShield
|
|
35
57
|
|
|
36
|
-
|
|
58
|
+
- [Try the online demo](https://demo.lesli.dev/)
|
|
59
|
+
- [Run the Docker demo](https://github.com/LesliTech/lesli-docker-demo)
|
|
37
60
|
|
|
38
|
-
|
|
61
|
+
<br />
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
### Requirements
|
|
66
|
+
|
|
67
|
+
- A Rails application with [Lesli](https://rubygems.org/gems/lesli)
|
|
68
|
+
- SQLite by default, or PostgreSQL when preferred by the host application
|
|
69
|
+
|
|
70
|
+
### Install LesliShield
|
|
71
|
+
|
|
72
|
+
Add the engine to the host Rails application and prepare its database:
|
|
73
|
+
|
|
74
|
+
```shell
|
|
39
75
|
bundle add lesli_shield
|
|
76
|
+
bin/rails db:prepare
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Mount the engine
|
|
40
80
|
|
|
81
|
+
Applications using Lesli's standard router mount LesliShield automatically at `/shield`:
|
|
41
82
|
|
|
42
|
-
|
|
43
|
-
|
|
83
|
+
```ruby
|
|
84
|
+
# config/routes.rb
|
|
85
|
+
Rails.application.routes.draw do
|
|
86
|
+
Lesli::Router.mount(self)
|
|
87
|
+
end
|
|
88
|
+
```
|
|
44
89
|
|
|
90
|
+
If the application does not use the standard Lesli router, mount the engine directly:
|
|
45
91
|
|
|
46
|
-
|
|
92
|
+
```ruby
|
|
93
|
+
# config/routes.rb
|
|
47
94
|
Rails.application.routes.draw do
|
|
48
95
|
mount LesliShield::Engine => "/shield"
|
|
49
96
|
end
|
|
50
97
|
```
|
|
51
98
|
|
|
52
|
-
|
|
53
|
-
|
|
99
|
+
Start Rails and visit [http://127.0.0.1:3000/shield](http://127.0.0.1:3000/shield):
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
bin/rails server
|
|
103
|
+
```
|
|
104
|
+
|
|
54
105
|
<br />
|
|
55
106
|
|
|
56
|
-
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
Clone LesliShield into the host application's `engines` directory:
|
|
110
|
+
|
|
111
|
+
```shell
|
|
112
|
+
cd RailsApp
|
|
113
|
+
mkdir -p engines
|
|
114
|
+
git clone https://github.com/LesliTech/LesliShield.git engines/LesliShield
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Reference the local engine from the host application's `Gemfile`:
|
|
57
118
|
|
|
58
119
|
```ruby
|
|
59
|
-
|
|
60
|
-
|
|
120
|
+
gem "lesli_shield", path: "engines/LesliShield"
|
|
121
|
+
```
|
|
61
122
|
|
|
62
|
-
|
|
63
|
-
gem "lesli", path: "engines/LesliShield"
|
|
123
|
+
Install dependencies, prepare the host database, and start Rails:
|
|
64
124
|
|
|
65
|
-
|
|
125
|
+
```shell
|
|
66
126
|
bundle install
|
|
127
|
+
bin/rails db:prepare
|
|
128
|
+
bin/rails server
|
|
129
|
+
```
|
|
67
130
|
|
|
68
|
-
|
|
69
|
-
rake lesli:db:setup
|
|
131
|
+
### Tests
|
|
70
132
|
|
|
133
|
+
From a complete Lesli development workspace, run the engine test suite from the LesliShield directory:
|
|
134
|
+
|
|
135
|
+
```shell
|
|
136
|
+
cd engines/LesliShield
|
|
137
|
+
bin/rails test
|
|
71
138
|
```
|
|
72
139
|
|
|
73
140
|
<br />
|
|
74
|
-
<hr />
|
|
75
|
-
<br />
|
|
76
|
-
|
|
77
|
-
### Demo
|
|
78
141
|
|
|
79
|
-
|
|
80
|
-
* [docker demo](https://github.com/LesliTech/lesli-docker-demo)
|
|
142
|
+
## Documentation
|
|
81
143
|
|
|
144
|
+
- [Lesli website](https://www.lesli.dev/)
|
|
145
|
+
- [Documentation](https://www.lesli.dev/engines/shield)
|
|
146
|
+
- [Release notes](https://github.com/LesliTech/LesliShield/releases)
|
|
147
|
+
- [Issue tracker](https://github.com/LesliTech/LesliShield/issues)
|
|
148
|
+
- [Source code](https://github.com/LesliTech/LesliShield)
|
|
82
149
|
|
|
83
|
-
|
|
84
|
-
* [website](https://www.lesli.dev/)
|
|
85
|
-
* [documentation](https://www.lesli.dev/engines/shield)
|
|
150
|
+
<br />
|
|
86
151
|
|
|
152
|
+
## Community
|
|
87
153
|
|
|
88
|
-
|
|
154
|
+
- [X: @LesliTech](https://x.com/LesliTech)
|
|
155
|
+
- [hello@lesli.tech](mailto:hello@lesli.tech)
|
|
156
|
+
- [https://www.lesli.tech](https://www.lesli.tech)
|
|
89
157
|
|
|
90
|
-
|
|
91
|
-
* [hello@lesli.tech](hello@lesli.tech)
|
|
92
|
-
* [https://www.lesli.tech](https://www.lesli.tech)
|
|
158
|
+
<br />
|
|
93
159
|
|
|
160
|
+
## License
|
|
94
161
|
|
|
95
|
-
### License
|
|
96
|
-
-------
|
|
97
162
|
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
98
163
|
|
|
99
164
|
This program is free software: you can redistribute it and/or modify
|
|
@@ -107,18 +172,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
107
172
|
GNU General Public License for more details.
|
|
108
173
|
|
|
109
174
|
You should have received a copy of the GNU General Public License
|
|
110
|
-
along with this program. If not, see
|
|
175
|
+
along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/).
|
|
111
176
|
|
|
112
|
-
|
|
113
|
-
<br />
|
|
114
|
-
<br />
|
|
177
|
+
The complete license text is available in the [license file](./license).
|
|
115
178
|
|
|
116
|
-
|
|
117
|
-
<img width="200" alt="Lesli logo" src="https://cdn.lesli.tech/lesli/brand/app-logo.svg" />
|
|
118
|
-
<h3 align="center" class="mt-0">
|
|
119
|
-
The Open-Source SaaS Development Framework for Ruby on Rails.
|
|
120
|
-
</h3>
|
|
121
|
-
</div>
|
|
179
|
+
---
|
|
122
180
|
|
|
123
181
|
<br />
|
|
124
182
|
<br />
|
|
183
|
+
|
|
184
|
+
<div align="center">
|
|
185
|
+
<img width="80" alt="Lesli icon" src="https://cdn.lesli.tech/lesli/brand/app-icon.svg" />
|
|
186
|
+
<h3 align="center">The Open-Source SaaS Development Framework for Ruby on Rails.</h3>
|
|
187
|
+
</div>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lesli_shield
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The Lesli Development Team
|
|
@@ -43,11 +43,13 @@ files:
|
|
|
43
43
|
- app/assets/javascripts/lesli_shield/registrations.js
|
|
44
44
|
- app/assets/javascripts/lesli_shield/sessions.js
|
|
45
45
|
- app/assets/stylesheets/lesli_shield/application.css
|
|
46
|
+
- app/assets/stylesheets/lesli_shield/application.tailwind.css
|
|
46
47
|
- app/assets/stylesheets/lesli_shield/confirmations.css
|
|
47
48
|
- app/assets/stylesheets/lesli_shield/devise/oauth.css
|
|
48
49
|
- app/assets/stylesheets/lesli_shield/passwords.css
|
|
49
50
|
- app/assets/stylesheets/lesli_shield/registrations.css
|
|
50
51
|
- app/assets/stylesheets/lesli_shield/sessions.css
|
|
52
|
+
- app/assets/stylesheets/lesli_shield/sessions.tailwind.css
|
|
51
53
|
- app/assets/stylesheets/lesli_shield/users.css
|
|
52
54
|
- app/controllers/lesli_shield/application_controller.rb
|
|
53
55
|
- app/controllers/lesli_shield/dashboards_controller.rb
|