Provision loads or creates ECH configs and returns outer names (for certificate management), but does not publish any ECH configs. The DNS module is used as a default for later publishing if needed.
(ctx caddy.Context)
| 78 | // management), but does not publish any ECH configs. The DNS module is used as |
| 79 | // a default for later publishing if needed. |
| 80 | func (ech *ECH) Provision(ctx caddy.Context) ([]string, error) { |
| 81 | ech.configsMu = new(sync.RWMutex) |
| 82 | |
| 83 | logger := ctx.Logger().Named("ech") |
| 84 | |
| 85 | // set up publication modules before we need to obtain a lock in storage, |
| 86 | // since this is strictly internal and doesn't require synchronization |
| 87 | for i, pub := range ech.Publication { |
| 88 | mods, err := ctx.LoadModule(pub, "PublishersRaw") |
| 89 | if err != nil { |
| 90 | return nil, fmt.Errorf("loading ECH publication modules: %v", err) |
| 91 | } |
| 92 | for _, modIface := range mods.(map[string]any) { |
| 93 | ech.Publication[i].publishers = append(ech.Publication[i].publishers, modIface.(ECHPublisher)) |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | // the rest of provisioning needs an exclusive lock so that instances aren't |
| 98 | // stepping on each other when setting up ECH configs |
| 99 | storage := ctx.Storage() |
| 100 | if err := storage.Lock(ctx, echStorageLockName); err != nil { |
| 101 | return nil, err |
| 102 | } |
| 103 | defer func() { |
| 104 | if err := storage.Unlock(ctx, echStorageLockName); err != nil { |
| 105 | logger.Error("unable to unlock ECH provisioning in storage", zap.Error(err)) |
| 106 | } |
| 107 | }() |
| 108 | |
| 109 | ech.configsMu.Lock() |
| 110 | defer ech.configsMu.Unlock() |
| 111 | |
| 112 | outerNames, err := ech.setConfigsFromStorage(ctx, logger) |
| 113 | if err != nil { |
| 114 | return nil, fmt.Errorf("loading configs from storage: %w", err) |
| 115 | } |
| 116 | |
| 117 | // see if we need to make any new ones based on the input configuration |
| 118 | for _, cfg := range ech.Configs { |
| 119 | publicName := strings.ToLower(strings.TrimSpace(cfg.PublicName)) |
| 120 | |
| 121 | if list, ok := ech.configs[publicName]; !ok || len(list) == 0 { |
| 122 | // no config with this public name was loaded, so create one |
| 123 | echCfg, err := generateAndStoreECHConfig(ctx, publicName) |
| 124 | if err != nil { |
| 125 | return nil, err |
| 126 | } |
| 127 | logger.Debug("generated new ECH config", |
| 128 | zap.String("public_name", echCfg.RawPublicName), |
| 129 | zap.Uint8("id", echCfg.ConfigID)) |
| 130 | ech.configs[publicName] = append(ech.configs[publicName], echCfg) |
| 131 | outerNames = append(outerNames, publicName) |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // convert the configs into a structure ready for the std lib to use |
| 136 | ech.updateKeyList() |
| 137 |
nothing calls this directly
no test coverage detected