Skip to content

Commit 0d86e8b

Browse files
authored
Add an old domain field to Cozy instances (#4556)
For the migration from Cozy to Twake Workplace, we need a way to redirect from the old domains to the new ones. So, an old domain field was added to the Cozy instances, and the stack will do the redirections from the old domains to the new ones. It works for the API endpoint, but also for the apps pages (eg old.mycozy.cloud -> new.twake.app). The old domain of a Cozy instance can be set with the `cozy-stack instances modify` command, or directly by modifying the `old_domain` field of the CouchDB document of the instance in the global database.
2 parents dd7b4f7 + 402f7b2 commit 0d86e8b

File tree

11 files changed

+65
-3
lines changed

11 files changed

+65
-3
lines changed

client/instances.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type Instance struct {
3030
Attrs struct {
3131
Domain string `json:"domain"`
3232
DomainAliases []string `json:"domain_aliases,omitempty"`
33+
OldDomain string `json:"old_domain,omitempty"`
3334
Prefix string `json:"prefix,omitempty"`
3435
Locale string `json:"locale"`
3536
UUID string `json:"uuid,omitempty"`
@@ -59,6 +60,7 @@ type Instance struct {
5960
type InstanceOptions struct {
6061
Domain string
6162
DomainAliases []string
63+
OldDomain string
6264
Locale string
6365
UUID string
6466
OIDCID string
@@ -148,6 +150,7 @@ func (ac *AdminClient) CreateInstance(opts *InstanceOptions) (*Instance, error)
148150
}
149151
q := url.Values{
150152
"Domain": {opts.Domain},
153+
"OldDomain": {opts.OldDomain},
151154
"Locale": {opts.Locale},
152155
"UUID": {opts.UUID},
153156
"OIDCID": {opts.OIDCID},
@@ -229,6 +232,7 @@ func (ac *AdminClient) ModifyInstance(opts *InstanceOptions) (*Instance, error)
229232
return nil, fmt.Errorf("Invalid domain: %s", domain)
230233
}
231234
q := url.Values{
235+
"OldDomain": {opts.OldDomain},
232236
"Locale": {opts.Locale},
233237
"UUID": {opts.UUID},
234238
"OIDCID": {opts.OIDCID},

cmd/instances.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
)
2727

2828
var flagDomainAliases []string
29+
var flagOldDomain string
2930
var flagListFields []string
3031
var flagLocale string
3132
var flagTimezone string
@@ -183,6 +184,7 @@ be used as the error message.
183184
in, err := ac.CreateInstance(&client.InstanceOptions{
184185
Domain: domain,
185186
DomainAliases: flagDomainAliases,
187+
OldDomain: flagOldDomain,
186188
Locale: flagLocale,
187189
UUID: flagUUID,
188190
OIDCID: flagOIDCID,
@@ -272,6 +274,7 @@ settings for a specified domain.
272274
opts := &client.InstanceOptions{
273275
Domain: domain,
274276
DomainAliases: flagDomainAliases,
277+
OldDomain: flagOldDomain,
275278
Locale: flagLocale,
276279
UUID: flagUUID,
277280
OIDCID: flagOIDCID,
@@ -1083,6 +1086,7 @@ func init() {
10831086
instanceCmdGroup.AddCommand(setAuthModeCmd)
10841087
instanceCmdGroup.AddCommand(cleanSessionsCmd)
10851088
addInstanceCmd.Flags().StringSliceVar(&flagDomainAliases, "domain-aliases", nil, "Specify one or more aliases domain for the instance (separated by ',')")
1089+
addInstanceCmd.Flags().StringVar(&flagOldDomain, "old-domain", "", "Old domain of the cozy instance")
10861090
addInstanceCmd.Flags().StringVar(&flagLocale, "locale", consts.DefaultLocale, "Locale of the new cozy instance")
10871091
addInstanceCmd.Flags().StringVar(&flagUUID, "uuid", "", "The UUID of the instance")
10881092
addInstanceCmd.Flags().StringVar(&flagOIDCID, "oidc_id", "", "The identifier for checking authentication from OIDC")
@@ -1104,6 +1108,7 @@ func init() {
11041108
addInstanceCmd.Flags().BoolVar(&flagTrace, "trace", false, "Show where time is spent")
11051109
addInstanceCmd.Flags().StringVar(&flagPassphrase, "passphrase", "", "Register the instance with this passphrase (useful for tests)")
11061110
modifyInstanceCmd.Flags().StringSliceVar(&flagDomainAliases, "domain-aliases", nil, "Specify one or more aliases domain for the instance (separated by ',')")
1111+
modifyInstanceCmd.Flags().StringVar(&flagOldDomain, "old-domain", "", "Old domain of the cozy instance")
11071112
modifyInstanceCmd.Flags().StringVar(&flagLocale, "locale", "", "New locale")
11081113
modifyInstanceCmd.Flags().StringVar(&flagUUID, "uuid", "", "New UUID")
11091114
modifyInstanceCmd.Flags().StringVar(&flagOIDCID, "oidc_id", "", "New identifier for checking authentication from OIDC")

docs/cli/cozy-stack_instances_add.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ $ cozy-stack instances add --passphrase cozy --apps drive,photos,settings,home,s
3838
--locale string Locale of the new cozy instance (default "en")
3939
--magic_link Enable authentication with magic links sent by email
4040
--oidc_id string The identifier for checking authentication from OIDC
41+
--old-domain string Old domain of the cozy instance
4142
--passphrase string Register the instance with this passphrase (useful for tests)
4243
--phone string The phone number of the owner
4344
--public-name string The public name of the owner

docs/cli/cozy-stack_instances_modify.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ cozy-stack instances modify <domain> [flags]
2828
--locale string New locale
2929
--magic_link Enable authentication with magic links sent by email
3030
--oidc_id string New identifier for checking authentication from OIDC
31+
--old-domain string Old domain of the cozy instance
3132
--onboarding-finished Force the finishing of the onboarding
3233
--phone string New phone number
3334
--public-name string New public name

model/instance/instance.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/cozy/cozy-stack/pkg/config/config"
2222
"github.com/cozy/cozy-stack/pkg/consts"
2323
"github.com/cozy/cozy-stack/pkg/couchdb"
24+
"github.com/cozy/cozy-stack/pkg/couchdb/mango"
2425
"github.com/cozy/cozy-stack/pkg/crypto"
2526
"github.com/cozy/cozy-stack/pkg/i18n"
2627
"github.com/cozy/cozy-stack/pkg/jsonapi"
@@ -48,8 +49,9 @@ const PBKDF2_SHA256 = 0
4849
type Instance struct {
4950
DocID string `json:"_id,omitempty"` // couchdb _id
5051
DocRev string `json:"_rev,omitempty"` // couchdb _rev
51-
Domain string `json:"domain"` // The main DNS domain, like example.cozycloud.cc
52+
Domain string `json:"domain"` // The main DNS domain, like example.twake.app
5253
DomainAliases []string `json:"domain_aliases,omitempty"`
54+
OldDomain string `json:"old_domain,omitempty"` // The old DNS domain, like old.mycozy.cloud
5355
Prefix string `json:"prefix,omitempty"` // Possible database prefix
5456
Locale string `json:"locale"` // The locale used on the server
5557
UUID string `json:"uuid,omitempty"` // UUID associated with the instance
@@ -724,6 +726,23 @@ func PaginatedList(limit int, startKey string, skip int) ([]*Instance, string, e
724726
return docs, "", nil
725727
}
726728

729+
func FindByOldDomain(oldDomain string) (*Instance, error) {
730+
var docs []*Instance
731+
req := &couchdb.FindRequest{
732+
UseIndex: "by-olddomain",
733+
Selector: mango.Equal("old_domain", oldDomain),
734+
Limit: 1,
735+
}
736+
err := couchdb.FindDocs(prefixer.GlobalPrefixer, consts.Instances, req, &docs)
737+
if err != nil {
738+
return nil, err
739+
}
740+
if len(docs) == 0 {
741+
return nil, ErrNotFound
742+
}
743+
return docs[0], nil
744+
}
745+
727746
// PickKey choose which of the Instance keys to use depending on token audience
728747
func (i *Instance) PickKey(audience string) ([]byte, error) {
729748
switch audience {

model/instance/lifecycle/create.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
type Options struct {
2929
Domain string
3030
DomainAliases []string
31+
OldDomain string
3132
Locale string
3233
UUID string
3334
OIDCID string
@@ -115,6 +116,7 @@ func Create(opts *Options) (*instance.Instance, error) {
115116
if err != nil {
116117
return nil, err
117118
}
119+
i.OldDomain = opts.OldDomain
118120
i.Prefix = "cozy" + hex.EncodeToString(prefix[:16])
119121
i.Locale = locale
120122
i.UUID = opts.UUID

model/instance/lifecycle/patch.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ func Patch(i *instance.Instance, opts *Options) error {
6868
needUpdate = true
6969
}
7070

71+
if opts.OldDomain != "" && opts.OldDomain != i.OldDomain {
72+
i.OldDomain = opts.OldDomain
73+
needUpdate = true
74+
}
75+
7176
if opts.UUID != "" && opts.UUID != i.UUID {
7277
i.UUID = opts.UUID
7378
needUpdate = true

pkg/couchdb/index.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ func IndexesByDoctype(doctype string) []*mango.Index {
318318
var globalIndexes = []*mango.Index{
319319
mango.MakeIndex(consts.Exports, "by-domain", mango.IndexDef{Fields: []string{"domain", "created_at"}}),
320320
mango.MakeIndex(consts.Instances, "by-oidcid", mango.IndexDef{Fields: []string{"oidc_id"}}),
321+
mango.MakeIndex(consts.Instances, "by-olddomain", mango.IndexDef{Fields: []string{"old_domain"}}),
321322
}
322323

323324
// secretIndexes is the index list required on the secret databases to run

web/instances/instances.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func createHandler(c echo.Context) error {
5656
var err error
5757
opts := &lifecycle.Options{
5858
Domain: c.QueryParam("Domain"),
59+
OldDomain: c.QueryParam("OldDomain"),
5960
Locale: c.QueryParam("Locale"),
6061
UUID: c.QueryParam("UUID"),
6162
OIDCID: c.QueryParam("OIDCID"),
@@ -164,6 +165,7 @@ func modifyHandler(c echo.Context) error {
164165
domain := c.Param("domain")
165166
opts := &lifecycle.Options{
166167
Domain: domain,
168+
OldDomain: c.QueryParam("OldDomain"),
167169
Locale: c.QueryParam("Locale"),
168170
UUID: c.QueryParam("UUID"),
169171
OIDCID: c.QueryParam("OIDCID"),

web/middlewares/instance.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,19 @@ func NeedInstance(next echo.HandlerFunc) echo.HandlerFunc {
3535
if err != nil {
3636
var errHTTP *echo.HTTPError
3737
switch err {
38-
case instance.ErrNotFound, instance.ErrIllegalDomain:
38+
case instance.ErrNotFound:
39+
if oldInstance, err := instance.FindByOldDomain(host); err == nil {
40+
newURL := url.URL{
41+
Scheme: oldInstance.Scheme(),
42+
Host: oldInstance.Domain,
43+
Path: c.Request().URL.Path,
44+
RawQuery: c.Request().URL.RawQuery,
45+
}
46+
return c.Redirect(http.StatusPermanentRedirect, newURL.String())
47+
}
48+
err = instance.ErrNotFound
49+
errHTTP = echo.NewHTTPError(http.StatusNotFound, err)
50+
case instance.ErrIllegalDomain:
3951
err = instance.ErrNotFound
4052
errHTTP = echo.NewHTTPError(http.StatusNotFound, err)
4153
default:

0 commit comments

Comments
 (0)