1
0
Fork 0
mirror of synced 2024-06-02 18:44:54 +12:00
budibase/packages/builder/src/pages/builder/portal/manage/auth/index.svelte

273 lines
6.8 KiB
Svelte

<script>
import GoogleLogo from "./_logos/Google.svelte"
import OidcLogo from "./_logos/OIDC.svelte"
import MicrosoftLogo from "assets/microsoft-logo.png"
import Auth0Logo from "assets/auth0-logo.png"
import OidcLogoPng from "assets/oidc-logo.png"
import {
Button,
Heading,
Divider,
Label,
notifications,
Layout,
Input,
Body,
Select,
} from "@budibase/bbui"
import { onMount } from "svelte"
import api from "builderStore/api"
import { organisation } from "stores/portal"
import { uuid } from "builderStore/uuid"
const ConfigTypes = {
Google: "google",
OIDC: "oidc",
// Github: "github",
// AzureAD: "ad",
}
const GoogleConfigFields = {
Google: ["clientID", "clientSecret", "callbackURL"],
}
const GoogleConfigLabels = {
Google: {
clientID: "Client ID",
clientSecret: "Client secret",
callbackURL: "Callback URL",
},
}
const OIDCConfigFields = {
Oidc: ["configUrl", "clientID", "clientSecret"],
}
const OIDCConfigLabels = {
Oidc: {
configUrl: "Config URL",
clientID: "Client ID",
clientSecret: "Client Secret",
},
}
let iconDropdownOptions = [
{
label: "Microsoft",
value: "Microsoft",
icon: MicrosoftLogo,
},
{ label: "Auth0", value: "Auth0", icon: Auth0Logo },
{ label: "OIDC", value: "Oidc", icon: OidcLogoPng },
{ label: "Upload your own", value: "Upload" },
]
let fileinput
let image
let google
let oidc
async function uploadLogo(file) {
let data = new FormData()
data.append("file", file)
const res = await api.post(
`/api/admin/configs/upload/oidc_logos/${file.name}`,
data,
{}
)
return await res.json()
}
const onFileSelected = e => {
let fileName = e.target.files[0].name
image = e.target.files[0]
providers.oidc.config.configs[0].logo = fileName
iconDropdownOptions.unshift({ label: fileName, value: fileName })
}
const providers = { google, oidc }
async function save(docs) {
// only if the user has provided an image, upload it.
image && uploadLogo(image)
let calls = []
docs.forEach(element => {
//Add a UUID here so each config is distinguishable when it arrives at the login page.
if (element.type === "oidc") {
element.config.configs.forEach(config => {
config.uuid = uuid()
})
}
calls.push(api.post(`/api/admin/configs`, element))
})
Promise.all(calls)
.then(responses => {
return Promise.all(
responses.map(response => {
return response.json()
})
)
})
.then(data => {
data.forEach(res => {
providers[res.type]._rev = res._rev
providers[res.type]._id = res._id
})
notifications.success(`Settings saved.`)
})
.catch(err => {
notifications.error(`Failed to update OAuth settings. ${err}`)
throw new Error(err.message)
})
}
onMount(async () => {
await organisation.init()
// fetch the configs for oauth
const googleResponse = await api.get(
`/api/admin/configs/${ConfigTypes.Google}`
)
const googleDoc = await googleResponse.json()
if (!googleDoc._id) {
providers.google = {
type: ConfigTypes.Google,
config: {},
}
} else {
providers.google = googleDoc
}
//Get the list of user uploaded logos and push it to the dropdown options.
//This needs to be done before the config call so they're available when the dropdown renders
const res = await api.get(`/api/admin/configs/oidc_logos`)
const configSettings = await res.json()
if (configSettings.config) {
const logoKeys = Object.keys(configSettings.config)
logoKeys.map(logoKey => {
const logoUrl = configSettings.config[logoKey]
iconDropdownOptions.unshift({
label: logoKey,
value: logoKey,
icon: logoUrl,
})
})
}
const oidcResponse = await api.get(`/api/admin/configs/${ConfigTypes.OIDC}`)
const oidcDoc = await oidcResponse.json()
if (!oidcDoc._id) {
providers.oidc = {
type: ConfigTypes.OIDC,
config: { configs: [{}] },
}
} else {
providers.oidc = oidcDoc
}
})
</script>
<Layout>
<Layout gap="XS" noPadding>
<Heading size="M">Authentication</Heading>
<Body>
Every budibase app comes with basic authentication (email/password)
included. You can add additional authentication methods from the options
below.
</Body>
</Layout>
{#if providers.google}
<Divider />
<Layout gap="XS" noPadding>
<Heading size="S">
<span>
<GoogleLogo />
Google
</span>
</Heading>
<Body size="S">
To allow users to authenticate using their Google accounts, fill out the
fields below.
</Body>
</Layout>
<Layout gap="XS" noPadding>
{#each GoogleConfigFields.Google as field}
<div class="form-row">
<Label size="L">{GoogleConfigLabels.Google[field]}</Label>
<Input bind:value={providers.google.config[field]} />
</div>
{/each}
</Layout>
{/if}
{#if providers.oidc}
<Divider />
<Layout gap="XS" noPadding>
<Heading size="S">
<span>
<OidcLogo />
OpenID Connect
</span>
</Heading>
<Body size="S">
To allow users to authenticate using OIDC, fill out the fields below.
</Body>
</Layout>
<Layout gap="XS" noPadding>
{#each OIDCConfigFields.Oidc as field}
<div class="form-row">
<Label size="L">{OIDCConfigLabels.Oidc[field]}</Label>
<Input bind:value={providers.oidc.config.configs[0][field]} />
</div>
{/each}
<br />
<Body size="S">
To customize your login button, fill out the fields below.
</Body>
<div class="form-row">
<Label size="L">Name</Label>
<Input bind:value={providers.oidc.config.configs[0].name} />
</div>
<div class="form-row">
<Label size="L">Icon</Label>
<Select
label=""
bind:value={providers.oidc.config.configs[0].logo}
options={iconDropdownOptions}
on:change={e => e.detail === "Upload" && fileinput.click()}
/>
</div>
<input
type="file"
accept=".jpg, .jpeg, .png"
on:change={e => onFileSelected(e)}
bind:this={fileinput}
/>
</Layout>
{/if}
<div>
<Button cta on:click={() => save([providers.google, providers.oidc])}
>Save</Button
>
</div>
</Layout>
<style>
.form-row {
display: grid;
grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
align-items: center;
}
span {
display: flex;
align-items: center;
gap: var(--spacing-s);
}
input {
display: none;
}
</style>