Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions api/internal/model/alias_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ var (
}
)

func GenerateAlias(format string, sufix string) string {
func GenerateAlias(format string, localPart string) string {
switch format {
case AliasFormatRandomChars:
return generateRandomChars()
case AliasFormatUUID:
return uuid.New().String()
case AliasFormatCatchAll:
return fmt.Sprintf("*+%s", sufix)
return fmt.Sprintf("*+%s", localPart)
case AliasFormatCustom:
return localPart
default:
return generateRandomWords()
}
Expand Down
6 changes: 3 additions & 3 deletions api/internal/service/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (s *Service) GetAliasByName(name string) (model.Alias, error) {
return alias, nil
}

func (s *Service) PostAlias(ctx context.Context, alias model.Alias, format string, domain string, sufix string) (model.Alias, error) {
func (s *Service) PostAlias(ctx context.Context, alias model.Alias, format string, domain string, localPart string) (model.Alias, error) {
sub, err := s.GetSubscription(context.Background(), alias.UserID)
if err != nil {
log.Printf("error fetching subscription: %s", err.Error())
Expand Down Expand Up @@ -142,7 +142,7 @@ func (s *Service) PostAlias(ctx context.Context, alias model.Alias, format strin
}
}

alias.Name = model.GenerateAlias(format, sufix) + "@" + domain
alias.Name = model.GenerateAlias(format, localPart) + "@" + domain
alias.CatchAll = true
alias, err = s.Store.PostAlias(ctx, alias)
if err != nil {
Expand All @@ -155,7 +155,7 @@ func (s *Service) PostAlias(ctx context.Context, alias model.Alias, format strin

// Standard alias
for range 5 {
alias.Name = model.GenerateAlias(format, "") + "@" + domain
alias.Name = model.GenerateAlias(format, localPart) + "@" + domain
alias, err = s.Store.PostAlias(ctx, alias)
if err != nil {
log.Printf("error creating standard alias: %s", err.Error())
Expand Down
4 changes: 2 additions & 2 deletions api/internal/transport/api/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (h *Handler) PostAlias(c *fiber.Ctx) error {
}

// Validate catch-all suffix
if req.Format == model.AliasFormatCatchAll && req.CatchAllSuffix == "" {
if req.Format == model.AliasFormatCatchAll && req.LocalPart == "" {
return c.Status(400).JSON(fiber.Map{
"error": ErrInvalidRequest,
})
Expand All @@ -233,7 +233,7 @@ func (h *Handler) PostAlias(c *fiber.Ctx) error {
FromName: req.FromName,
}

alias, err = h.Service.PostAlias(c.Context(), alias, req.Format, domain, req.CatchAllSuffix)
alias, err = h.Service.PostAlias(c.Context(), alias, req.Format, domain, req.LocalPart)
if err != nil {
return c.Status(400).JSON(fiber.Map{
"error": err.Error(),
Expand Down
14 changes: 7 additions & 7 deletions api/internal/transport/api/req.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ type SubscriptionReq struct {
}

type AliasReq struct {
Description string `json:"description"`
Enabled bool `json:"enabled"`
Recipients string `json:"recipients" validate:"required"`
FromName string `json:"from_name"`
Format string `json:"format"`
Domain string `json:"domain" validate:"required"`
CatchAllSuffix string `json:"catch_all_suffix" validate:"omitempty,alphanum,min=6,max=12"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Recipients string `json:"recipients" validate:"required"`
FromName string `json:"from_name"`
Format string `json:"format"`
Domain string `json:"domain" validate:"required"`
LocalPart string `json:"local_part" validate:"omitempty,alphanum,min=6,max=12"`
}

type RecipientReq struct {
Expand Down
83 changes: 71 additions & 12 deletions app/src/components/AliasCreate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,31 @@
Alias suffix (6-12 alphanumeric chars.):
</label>
<input
v-model="alias.catch_all_suffix"
v-bind:class="{ 'error': errorCatchAllSuffix }"
v-model="alias.local_part"
v-bind:class="{ 'error': errorLocalPart }"
id="alias_catch_all_suffix"
type="text"
>
<p v-if="errorCatchAllSuffix" class="error">Wildcard suffix must be between 6 and 12 characters</p>
<p v-if="errorLocalPart" class="error">Wildcard suffix must be between 6 and 12 characters</p>
<p class="text-primary mb-1">
*+{{ alias.catch_all_suffix }}@{{ alias.domain }}
*+{{ alias.local_part }}@{{ alias.domain }}
</p>
</div>
</div>
<div v-if="alias.format === 'custom'">
<div class="mb-3">
<label for="alias_custom_alias">
Custom alias (6-12 alphanumeric chars.):
</label>
<input
v-model="alias.local_part"
v-bind:class="{ 'error': errorLocalPart }"
id="alias_custom_alias"
type="text"
>
<p v-if="errorLocalPart" class="error">Custom alias must be between 6 and 12 characters</p>
</div>
</div>
<div>
<div class="pb-5">
<label for="alias_description">
Expand Down Expand Up @@ -169,7 +183,7 @@ const alias = ref({
recipients: '',
domain: envDomains[0],
catch_all: props.catchAll ? 'true' : 'false',
catch_all_suffix: ''
local_part: ''
})
const recipients = ref(props.recipients)
const settings = ref(props.settings)
Expand All @@ -188,7 +202,7 @@ const formats = ref([{
}])
const error = ref('')
const errorRecipients = ref('')
const errorCatchAllSuffix = ref(false)
const errorLocalPart = ref(false)
const loading = ref(false)

const postAlias = async () => {
Expand Down Expand Up @@ -235,7 +249,7 @@ const postAlias = async () => {
const close = () => {
resetAlias()
error.value = ''
errorCatchAllSuffix.value = false
errorLocalPart.value = false

document.removeEventListener('keydown', handleKeydown)

Expand Down Expand Up @@ -265,6 +279,12 @@ const addEvents = () => {
multiselect.element.on('change', (val: any) => {
errorRecipients.value = val.length === 0 ? 'Select one or more recipients' : ''
})

const domainSelect = document.getElementById('alias_domain') as HTMLSelectElement
domainSelect.addEventListener('change', updateFormats)

const formatElement = document.getElementById('alias_format') as HTMLInputElement
formatElement.addEventListener('change', updateFormat)
}

const handleKeydown = (event: KeyboardEvent) => {
Expand All @@ -285,13 +305,52 @@ const validate = (rcps: string) => {
return false
}

if (props.catchAll) {
errorCatchAllSuffix.value = alias.value.catch_all_suffix.length < 6 || alias.value.catch_all_suffix.length > 12
if (props.catchAll || alias.value.format === 'custom') {
errorLocalPart.value = alias.value.local_part.length < 6 || alias.value.local_part.length > 12
} else {
errorCatchAllSuffix.value = false
errorLocalPart.value = false
}

return !errorCatchAllSuffix.value
return !errorLocalPart.value
}

const updateFormats = () => {
const select = document.getElementById('alias_domain') as HTMLSelectElement
const selectedOption = select.options[select.selectedIndex]
const domain = selectedOption.getAttribute('domain')
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(domain || '')

if (isUUID) {
formats.value = [{
name: 'Words',
value: 'words'
}, {
name: 'Random',
value: 'random'
}, {
name: 'UUID',
value: 'uuid'
}, {
name: 'Custom',
value: 'custom'
}]
} else {
formats.value = [{
name: 'Words',
value: 'words'
}, {
name: 'Random',
value: 'random'
}, {
name: 'UUID',
value: 'uuid'
}]
}
}

const updateFormat = () => {
const formatElement = document.getElementById('alias_format') as HTMLInputElement
alias.value.format = formatElement.value
}

const resetAlias = () => {
Expand All @@ -303,7 +362,7 @@ const resetAlias = () => {
recipients: '',
domain: props.settings.domain || envDomains[0],
catch_all: props.catchAll ? 'true' : 'false',
catch_all_suffix: ''
local_part: ''
}
}

Expand Down