Merge branch 'ngoduykhanh:master' into master
This commit is contained in:
		
						commit
						686ff85ea9
					
				|  | @ -31,7 +31,7 @@ function renderClientList(data) { | ||||||
|                                 <div class="btn-group">       |                                 <div class="btn-group">       | ||||||
|                                     <button type="button" class="btn btn-outline-secondary btn-sm" data-toggle="modal" |                                     <button type="button" class="btn btn-outline-secondary btn-sm" data-toggle="modal" | ||||||
|                                         data-target="#modal_qr_client" data-clientid="${obj.Client.id}" |                                         data-target="#modal_qr_client" data-clientid="${obj.Client.id}" | ||||||
|                                         data-clientname="${obj.Client.name}">Scan</button> |                                         data-clientname="${obj.Client.name}" ${obj.QRCode != "" ? '' : ' disabled'}>Scan</button> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="btn-group">       |                                 <div class="btn-group">       | ||||||
|                                     <button type="button" class="btn btn-outline-secondary btn-sm" data-toggle="modal" |                                     <button type="button" class="btn btn-outline-secondary btn-sm" data-toggle="modal" | ||||||
|  |  | ||||||
|  | @ -171,23 +171,51 @@ func NewClient(db store.IStore) echo.HandlerFunc { | ||||||
| 		client.ID = guid.String() | 		client.ID = guid.String() | ||||||
| 
 | 
 | ||||||
| 		// gen Wireguard key pair
 | 		// gen Wireguard key pair
 | ||||||
| 		key, err := wgtypes.GeneratePrivateKey() | 		if client.PublicKey == "" { | ||||||
| 		if err != nil { | 			key, err := wgtypes.GeneratePrivateKey() | ||||||
| 			log.Error("Cannot generate wireguard key pair: ", err) | 			if err != nil { | ||||||
| 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"}) | 				log.Error("Cannot generate wireguard key pair: ", err) | ||||||
|  | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot generate Wireguard key pair"}) | ||||||
|  | 			} | ||||||
|  | 			client.PrivateKey = key.String() | ||||||
|  | 			client.PublicKey = key.PublicKey().String() | ||||||
|  | 		} else { | ||||||
|  | 			_, err := wgtypes.ParseKey(client.PublicKey) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Error("Cannot verify wireguard public key: ", err) | ||||||
|  | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify Wireguard public key"}) | ||||||
|  | 			} | ||||||
|  | 			// check for duplicates
 | ||||||
|  | 			clients, err := db.GetClients(false) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Error("Cannot get clients for duplicate check") | ||||||
|  | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get clients for duplicate check"}) | ||||||
|  | 			} | ||||||
|  | 			for _, other := range clients { | ||||||
|  | 				if other.Client.PublicKey == client.PublicKey { | ||||||
|  | 					log.Error("Duplicate Public Key") | ||||||
|  | 					return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Duplicate Public Key"}) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		presharedKey, err := wgtypes.GenerateKey() | 		if client.PresharedKey == "" { | ||||||
| 		if err != nil { | 			presharedKey, err := wgtypes.GenerateKey() | ||||||
| 			log.Error("Cannot generated preshared key: ", err) | 			if err != nil { | ||||||
| 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ | 				log.Error("Cannot generated preshared key: ", err) | ||||||
| 				false, "Cannot generate Wireguard preshared key", | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ | ||||||
| 			}) | 					false, "Cannot generate Wireguard preshared key", | ||||||
|  | 				}) | ||||||
|  | 			} | ||||||
|  | 			client.PresharedKey = presharedKey.String() | ||||||
|  | 		} else { | ||||||
|  | 			_, err := wgtypes.ParseKey(client.PresharedKey) | ||||||
|  | 			if err != nil { | ||||||
|  | 				log.Error("Cannot verify wireguard preshared key: ", err) | ||||||
|  | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify Wireguard preshared key"}) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		client.PrivateKey = key.String() |  | ||||||
| 		client.PublicKey = key.PublicKey().String() |  | ||||||
| 		client.PresharedKey = presharedKey.String() |  | ||||||
| 		client.CreatedAt = time.Now().UTC() | 		client.CreatedAt = time.Now().UTC() | ||||||
| 		client.UpdatedAt = client.CreatedAt | 		client.UpdatedAt = client.CreatedAt | ||||||
| 
 | 
 | ||||||
|  | @ -227,18 +255,25 @@ func EmailClient(db store.IStore, mailer emailer.Emailer, emailSubject, emailCon | ||||||
| 		config := util.BuildClientConfig(*clientData.Client, server, globalSettings) | 		config := util.BuildClientConfig(*clientData.Client, server, globalSettings) | ||||||
| 
 | 
 | ||||||
| 		cfg_att := emailer.Attachment{"wg0.conf", []byte(config)} | 		cfg_att := emailer.Attachment{"wg0.conf", []byte(config)} | ||||||
| 		qrdata, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(clientData.QRCode, "data:image/png;base64,")) | 		var attachments []emailer.Attachment | ||||||
| 		if err != nil { | 		if clientData.Client.PrivateKey != "" { | ||||||
| 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "decoding: " + err.Error()}) | 			qrdata, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(clientData.QRCode, "data:image/png;base64,")) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "decoding: " + err.Error()}) | ||||||
|  | 			} | ||||||
|  | 			qr_att := emailer.Attachment{"wg.png", qrdata} | ||||||
|  | 			attachments = []emailer.Attachment{cfg_att, qr_att} | ||||||
|  | 		} else { | ||||||
|  | 			attachments = []emailer.Attachment{cfg_att} | ||||||
| 		} | 		} | ||||||
| 		qr_att := emailer.Attachment{"wg.png", qrdata} |  | ||||||
| 		err = mailer.Send( | 		err = mailer.Send( | ||||||
| 			clientData.Client.Name, | 			clientData.Client.Name, | ||||||
| 			payload.Email, | 			payload.Email, | ||||||
| 			emailSubject, | 			emailSubject, | ||||||
| 			emailContent, | 			emailContent, | ||||||
| 			[]emailer.Attachment{cfg_att, qr_att}, | 			attachments, | ||||||
| 		) | 		) | ||||||
|  | 
 | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) | 			return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -159,7 +159,7 @@ func (o *JsonDB) GetClients(hasQRCode bool) ([]model.ClientData, error) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// generate client qrcode image in base64
 | 		// generate client qrcode image in base64
 | ||||||
| 		if hasQRCode { | 		if hasQRCode && client.PrivateKey != "" { | ||||||
| 			server, _ := o.GetServer() | 			server, _ := o.GetServer() | ||||||
| 			globalSettings, _ := o.GetGlobalSettings() | 			globalSettings, _ := o.GetGlobalSettings() | ||||||
| 
 | 
 | ||||||
|  | @ -189,7 +189,7 @@ func (o *JsonDB) GetClientByID(clientID string, hasQRCode bool) (model.ClientDat | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// generate client qrcode image in base64
 | 	// generate client qrcode image in base64
 | ||||||
| 	if hasQRCode { | 	if hasQRCode && client.PrivateKey != "" { | ||||||
| 		server, _ := o.GetServer() | 		server, _ := o.GetServer() | ||||||
| 		globalSettings, _ := o.GetGlobalSettings() | 		globalSettings, _ := o.GetGlobalSettings() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -193,6 +193,21 @@ | ||||||
|                                     </label> |                                     </label> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|  |                             <details> | ||||||
|  |                                 <summary>Public and Preshared Keys</summary> | ||||||
|  |                                 <div class="form-group" style="margin-top: 1rem"> | ||||||
|  |                                     <label for="client_public_key" class="control-label"> | ||||||
|  |                                         Public Key | ||||||
|  |                                     </label> | ||||||
|  |                                     <input type="text" class="form-control" id="client_public_key" name="client_public_key" placeholder="Autogenerated (insecure)" aria-invalid="false"> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div class="form-group"> | ||||||
|  |                                     <label for="client_preshared_key" class="control-label"> | ||||||
|  |                                         Preshared Key | ||||||
|  |                                     </label> | ||||||
|  |                                     <input type="text" class="form-control" id="client_preshared_key" name="client_preshared_key" placeholder="Autogenerated"> | ||||||
|  |                                 </div> | ||||||
|  |                             </details> | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="modal-footer justify-content-between"> |                         <div class="modal-footer justify-content-between"> | ||||||
|                             <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> |                             <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | ||||||
|  | @ -323,9 +338,12 @@ | ||||||
|             if ($("#enabled").is(':checked')){ |             if ($("#enabled").is(':checked')){ | ||||||
|                 enabled = true; |                 enabled = true; | ||||||
|             } |             } | ||||||
|  |             const public_key = $("#client_public_key").val(); | ||||||
|  |             const preshared_key = $("#client_preshared_key").val(); | ||||||
| 
 | 
 | ||||||
|             const data = {"name": name, "email": email, "allocated_ips": allocated_ips, "allowed_ips": allowed_ips, |             const data = {"name": name, "email": email, "allocated_ips": allocated_ips, "allowed_ips": allowed_ips, | ||||||
|                 "extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enabled": enabled}; |                 "extra_allowed_ips": extra_allowed_ips, "use_server_dns": use_server_dns, "enabled": enabled, | ||||||
|  |                 "public_key": public_key, "preshared_key": preshared_key}; | ||||||
| 
 | 
 | ||||||
|             $.ajax({ |             $.ajax({ | ||||||
|                 cache: false, |                 cache: false, | ||||||
|  | @ -443,6 +461,8 @@ | ||||||
|             $("#modal_new_client").on('shown.bs.modal', function (e) { |             $("#modal_new_client").on('shown.bs.modal', function (e) { | ||||||
|                 $("#client_name").val(""); |                 $("#client_name").val(""); | ||||||
|                 $("#client_email").val(""); |                 $("#client_email").val(""); | ||||||
|  |                 $("#client_public_key").val(""); | ||||||
|  |                 $("#client_preshared_key").val(""); | ||||||
|                 $("#client_allocated_ips").importTags(''); |                 $("#client_allocated_ips").importTags(''); | ||||||
|                 $("#client_extra_allowed_ips").importTags(''); |                 $("#client_extra_allowed_ips").importTags(''); | ||||||
|                 updateIPAllocationSuggestion(); |                 updateIPAllocationSuggestion(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue