浏览代码

Merge branch 'master' into kris/add_support_for_restore_ui

pull/20/head
父节点
当前提交
83011f4f01
共有 17 个文件被更改,包括 201 次插入104 次删除
  1. +1
    -0
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +55
    -33
      bubble-server/src/main/java/bubble/dao/device/DeviceDAO.java
  3. +10
    -4
      bubble-server/src/main/java/bubble/model/device/Device.java
  4. +0
    -6
      bubble-server/src/main/java/bubble/resources/BubbleMagicResource.java
  5. +16
    -0
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  6. +2
    -5
      bubble-server/src/main/java/bubble/resources/account/VpnConfigResource.java
  7. +4
    -0
      bubble-server/src/main/java/bubble/service/account/StandardSyncPasswordService.java
  8. +3
    -3
      bubble-server/src/main/java/bubble/service/cloud/NodeProgressMeterConstants.java
  9. +27
    -1
      bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java
  10. +1
    -1
      bubble-server/src/main/resources/META-INF/bubble/bubble.properties
  11. +11
    -11
      bubble-server/src/main/resources/bubble/node_progress_meter_ticks.json
  12. +4
    -5
      bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties
  13. +1
    -0
      bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties
  14. +61
    -29
      bubble-server/src/main/resources/packer/roles/algo/files/algo_refresh_users.sh
  15. +1
    -2
      bubble-server/src/main/resources/packer/roles/algo/files/algo_refresh_users_monitor.sh
  16. +2
    -2
      bubble-server/src/main/resources/packer/roles/mitmproxy/files/bubble_conn_check.py
  17. +2
    -2
      bubble-server/src/test/resources/models/tests/auth/device_crud.json

+ 1
- 0
bubble-server/src/main/java/bubble/ApiConstants.java 查看文件

@@ -92,6 +92,7 @@ public class ApiConstants {
public static final String AUTH_ENDPOINT = "/auth";
public static final String EP_ACTIVATE = "/activate";
public static final String EP_CONFIGS = "/configs";
public static final String EP_READY = "/ready";
public static final String EP_REGISTER = "/register";
public static final String EP_LOGIN = "/login";
public static final String EP_APP_LOGIN = "/appLogin";


+ 55
- 33
bubble-server/src/main/java/bubble/dao/device/DeviceDAO.java 查看文件

@@ -10,8 +10,8 @@ import bubble.dao.app.AppDataDAO;
import bubble.model.device.BubbleDeviceType;
import bubble.model.device.Device;
import bubble.server.BubbleConfiguration;
import lombok.NonNull;
import bubble.service.cloud.DeviceIdService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,24 +20,29 @@ import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.io.File;
import java.util.List;
import java.util.Optional;

import static bubble.ApiConstants.HOME_DIR;
import static bubble.model.device.Device.UNINITIALIZED_DEVICE_LIKE;
import static bubble.model.device.Device.newUninitializedDevice;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.daemon.ZillaRuntime.now;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.io.FileUtil.touch;
import static org.cobbzilla.util.reflect.ReflectionUtil.copy;
import static org.cobbzilla.util.system.Sleep.sleep;

@Repository @Slf4j
public class DeviceDAO extends AccountOwnedEntityDAO<Device> {

private static final File VPN_REFRESH_USERS_FILE = new File(HOME_DIR, ".algo_refresh_users");
private static final short SPARE_DEVICES_PER_ACCOUNT_MAX = 10;
private static final short SPARE_DEVICES_PER_ACCOUNT_THRESHOLD = 5;
private static final short SPARE_DEVICES_PER_ACCOUNT_THRESHOLD = 10;
private static final long DEVICE_INIT_TIMEOUT = MINUTES.toMillis(5);

@Autowired private BubbleConfiguration configuration;
@Autowired private AccountDAO accountDAO;
@Autowired private AppDataDAO dataDAO;
@Autowired private DeviceIdService deviceIdService;

@@ -58,38 +63,54 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> {
return super.preCreate(device);
}

private static final Object createLock = new Object();

@Transactional
@Override public Device create(@NonNull final Device device) {
if (device.uninitialized()) return super.create(device);
device.initDeviceType();

final var accountUuid = device.getAccount();
final var uninitializedDevices = findByAccountAndUninitialized(accountUuid);

var newDevicesCreated = false;
if (uninitializedDevices.size() <= SPARE_DEVICES_PER_ACCOUNT_THRESHOLD
&& !configuration.getBean(AccountDAO.class).findByUuid(accountUuid).isRoot()) {
newDevicesCreated = ensureAllSpareDevices(accountUuid, device.getNetwork());
synchronized (createLock) {
if (device.uninitialized()) return super.create(device);
device.initDeviceType();

final var accountUuid = device.getAccount();
var uninitializedDevices = findByAccountAndUninitialized(accountUuid);

if (uninitializedDevices.size() <= SPARE_DEVICES_PER_ACCOUNT_THRESHOLD
&& !configuration.getBean(AccountDAO.class).findByUuid(accountUuid).isRoot()) {
if (ensureAllSpareDevices(accountUuid, device.getNetwork())) refreshVpnUsers();
}

final Device result;
uninitializedDevices = findByAccountAndUninitialized(accountUuid);
if (uninitializedDevices.isEmpty()) {
log.warn("create: no uninitialized devices for account " + accountUuid);
// just create the device now:
device.initTotpKey();
result = super.create(device);

} else {
final Device uninitialized;
Optional<Device> availableDevice = uninitializedDevices.stream().filter(Device::configsOk).findAny();
final long start = now();
while (availableDevice.isEmpty() && now() - start < DEVICE_INIT_TIMEOUT) {
if (configuration.testMode()) {
log.warn("create: no available uninitialized devices and in test mode, using first uninitialized device...");
availableDevice = Optional.of(uninitializedDevices.get(0));
} else {
// wait for configs to be ok
log.warn("create: no available uninitialized devices, waiting...");
sleep(SECONDS.toMillis(5), "waiting for available uninitialized device");
availableDevice = uninitializedDevices.stream().filter(Device::configsOk).findAny();
}
}
if (availableDevice.isEmpty()) return die("create: timeout waiting for available uninitialized device");
uninitialized = availableDevice.get();
copy(uninitialized, device);
result = super.update(uninitialized);
}

deviceIdService.setDeviceSecurityLevel(result);
return result;
}

final Device result;
// run the above creation of spare devices in parallel, but if there were no spare devices loaded before that,
// create a brand new entry here:
if (uninitializedDevices.isEmpty()) {
log.info("create: no uninitialized devices for account " + accountUuid);
// just create the device now:
device.initTotpKey();
result = super.create(device);
newDevicesCreated = true;
} else {
final var uninitialized = uninitializedDevices.get(0);
copy(uninitialized, device);
result = super.update(uninitialized);
}

if (newDevicesCreated) refreshVpnUsers();
deviceIdService.setDeviceSecurityLevel(result);
return result;
}

@Override @NonNull public Device update(@NonNull final Device updateRequest) {
@@ -100,6 +121,7 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> {
toUpdate.update(updateRequest);
final var updated = super.update(toUpdate);
deviceIdService.setDeviceSecurityLevel(updated);
refreshVpnUsers();
return updated;
}



+ 10
- 4
bubble-server/src/main/java/bubble/model/device/Device.java 查看文件

@@ -4,6 +4,7 @@
*/
package bubble.model.device;

import bubble.ApiConstants;
import bubble.model.account.Account;
import bubble.model.account.HasAccount;
import bubble.model.cloud.BubbleNetwork;
@@ -18,12 +19,11 @@ import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.hibernate.annotations.Type;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.*;
import javax.validation.constraints.Size;

import java.io.File;

import static bubble.ApiConstants.EP_DEVICES;
import static bubble.model.device.BubbleDeviceType.other;
import static bubble.model.device.BubbleDeviceType.uninitialized;
@@ -50,6 +50,12 @@ public class Device extends IdentifiableBase implements HasAccount {
public static final String UNINITIALIZED_DEVICE = "__uninitialized_device__";
public static final String UNINITIALIZED_DEVICE_LIKE = UNINITIALIZED_DEVICE+"%";

public static final String VPN_CONFIG_PATH = ApiConstants.HOME_DIR + "/configs/localhost/wireguard/";

public File qrFile () { return new File(Device.VPN_CONFIG_PATH+getUuid()+".png"); }
public File vpnConfFile () { return new File(Device.VPN_CONFIG_PATH+getUuid()+".conf"); }
public boolean configsOk () { return qrFile().exists() && vpnConfFile().exists(); }

public Device (Device other) { copy(this, other, CREATE_FIELDS); }

public Device (String uuid) { setUuid(uuid); }


+ 0
- 6
bubble-server/src/main/java/bubble/resources/BubbleMagicResource.java 查看文件

@@ -4,11 +4,8 @@
*/
package bubble.resources;

import bubble.server.BubbleConfiguration;
import bubble.service.cloud.RequestCoordinationService;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.Consumes;
@@ -28,9 +25,6 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.ok;
@Service @Slf4j
public class BubbleMagicResource {

@Autowired private BubbleConfiguration configuration;
@Autowired private RequestCoordinationService requestService;

@GET
public Response get(@Context ContainerRequest ctx) {
return ok("you are ok. the magic is ok too.");


+ 16
- 0
bubble-server/src/main/java/bubble/resources/account/AuthResource.java 查看文件

@@ -13,6 +13,7 @@ import bubble.dao.bill.AccountPaymentMethodDAO;
import bubble.dao.bill.BubblePlanDAO;
import bubble.dao.cloud.BubbleNodeDAO;
import bubble.dao.cloud.BubbleNodeKeyDAO;
import bubble.dao.device.DeviceDAO;
import bubble.model.CertType;
import bubble.model.account.*;
import bubble.model.account.message.*;
@@ -92,6 +93,7 @@ public class AuthResource {
@Autowired private StandardAuthenticatorService authenticatorService;
@Autowired private PromotionService promoService;
@Autowired private DeviceIdService deviceIdService;
@Autowired private DeviceDAO deviceDAO;
@Autowired private BubbleNodeKeyDAO nodeKeyDAO;
@Autowired private NodeManagerService nodeManagerService;

@@ -107,6 +109,20 @@ public class AuthResource {
return ok(configuration.getPublicSystemConfigs());
}

@GET @Path(EP_READY)
public Response getNodeIsReady(@Context ContainerRequest ctx) {
try {
if (deviceDAO.findByAccountAndUninitialized(accountDAO.getFirstAdmin().getUuid())
.stream()
.anyMatch(Device::configsOk)) {
return ok();
}
} catch (Exception e) {
log.warn("getNodeIsReady: "+shortError(e));
}
return invalid("err.node.notReady");
}

@GET @Path(EP_ACTIVATE)
public Response isActivated(@Context ContainerRequest ctx) { return ok(accountDAO.activated()); }



+ 2
- 5
bubble-server/src/main/java/bubble/resources/account/VpnConfigResource.java 查看文件

@@ -4,7 +4,6 @@
*/
package bubble.resources.account;

import bubble.ApiConstants;
import bubble.model.account.Account;
import bubble.model.device.Device;
import lombok.extern.slf4j.Slf4j;
@@ -30,14 +29,12 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.*;
@Slf4j
public class VpnConfigResource {

public static final String VPN_CONFIG_PATH = ApiConstants.HOME_DIR + "/configs/localhost/wireguard/";

private Device device;

public VpnConfigResource(Device device) { this.device = device; }

public File getQRfile() {
final File qrFile = new File(VPN_CONFIG_PATH+device.getUuid()+".png");
final File qrFile = device.qrFile();
if (!qrFile.exists()) {
// todo: try to regenerate algo users?
log.error("qrCode: file not found: "+abs(qrFile));
@@ -47,7 +44,7 @@ public class VpnConfigResource {
}

public File getVpnConfFile() {
final File confFile = new File(VPN_CONFIG_PATH+device.getUuid()+".conf");
final File confFile = device.vpnConfFile();
if (!confFile.exists()) {
// todo: try to regenerate algo users?
log.error("confFile: file not found: "+abs(confFile));


+ 4
- 0
bubble-server/src/main/java/bubble/service/account/StandardSyncPasswordService.java 查看文件

@@ -35,6 +35,10 @@ public class StandardSyncPasswordService implements SyncPasswordService {
log.warn("syncPassword: thisNetwork was null, sync_password is impossible");
return;
}
if (!account.admin()) {
log.info("syncPassword: not syncing non-admin password");
return;
}
final AnsibleInstallType installType = thisNetwork.getInstallType();
final SyncPasswordNotification notification = new SyncPasswordNotification(account);
if (installType == AnsibleInstallType.sage) {


+ 3
- 3
bubble-server/src/main/java/bubble/service/cloud/NodeProgressMeterConstants.java 查看文件

@@ -60,9 +60,9 @@ public class NodeProgressMeterConstants {
{METER_TICK_LAUNCHING_NODE, 1},
{METER_TICK_PREPARING_ROLES, 5},
{METER_TICK_PREPARING_INSTALL, 7},
{METER_TICK_STARTING_INSTALL, 33},
{METER_TICK_COPYING_ANSIBLE, 34},
{METER_TICK_RUNNING_ANSIBLE, 37}
{METER_TICK_STARTING_INSTALL, 23},
{METER_TICK_COPYING_ANSIBLE, 24},
{METER_TICK_RUNNING_ANSIBLE, 27}
});

public static List<NodeProgressMeterTick> getStandardTicks(NewNodeNotification nn) {


+ 27
- 1
bubble-server/src/main/java/bubble/service/cloud/StandardNetworkService.java 查看文件

@@ -4,6 +4,7 @@
*/
package bubble.service.cloud;

import bubble.client.BubbleNodeClient;
import bubble.cloud.CloudAndRegion;
import bubble.cloud.compute.ComputeServiceDriver;
import bubble.dao.account.AccountDAO;
@@ -74,7 +75,8 @@ import static bubble.service.boot.StandardSelfNodeService.*;
import static bubble.service.cloud.NodeProgressMeter.getProgressMeterKey;
import static bubble.service.cloud.NodeProgressMeter.getProgressMeterPrefix;
import static bubble.service.cloud.NodeProgressMeterConstants.*;
import static java.util.concurrent.TimeUnit.*;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
import static org.cobbzilla.util.daemon.Await.awaitAll;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
@@ -104,6 +106,7 @@ public class StandardNetworkService implements NetworkService {
private static final long NET_DEADLOCK_TIMEOUT = MINUTES.toMillis(20);
private static final long PLAN_ENABLE_TIMEOUT = PURCHASE_DELAY + SECONDS.toMillis(10);
private static final long NODE_START_JOB_TIMEOUT = MINUTES.toMillis(30);
private static final long NODE_READY_TIMEOUT = MINUTES.toMillis(6);

@Autowired private AccountDAO accountDAO;
@Autowired private AccountSshKeyDAO sshKeyDAO;
@@ -346,6 +349,28 @@ public class StandardNetworkService implements NetworkService {
}
if (!setupOk) return die("newNode: error setting up, all retries failed for node: "+node.getUuid());

// wait for node to be ready
final long readyStart = now();
boolean ready = false;
BubbleNodeClient nodeClient = null;
while (now() - readyStart < NODE_READY_TIMEOUT) {
sleep(SECONDS.toMillis(2), "newNode: waiting for node ("+node.id()+") to be ready");
if (nodeKeyDAO.findFirstByNode(node.getUuid()) == null) continue;
try {
if (nodeClient == null) nodeClient = node.getApiQuickClient(configuration);
if (nodeClient.get(AUTH_ENDPOINT + EP_READY).isSuccess()) {
log.info("newNode: node ("+node.id()+") is ready!");
ready = true;
break;
}
} catch (Exception e) {
log.warn("newNode: node ("+node.id()+") error checking if ready: "+shortError(e));
}
}
if (!ready) {
return die("newNode: timeout waiting for node ("+node.id()+") to be ready");
}

// we are good.
final BubbleNetworkState finalState = nn.hasRestoreKey() ? BubbleNetworkState.restoring : BubbleNetworkState.running;
if (network.getState() != finalState) {
@@ -355,6 +380,7 @@ public class StandardNetworkService implements NetworkService {
node.setState(BubbleNodeState.running);
nodeDAO.update(node);
progressMeter.completed();
log.info("newNode: ready in "+formatDuration(now() - start));

} catch (Exception e) {
log.error("newNode: "+e, e);


+ 1
- 1
bubble-server/src/main/resources/META-INF/bubble/bubble.properties 查看文件

@@ -1 +1 @@
bubble.version=0.12.5
bubble.version=0.12.6

+ 11
- 11
bubble-server/src/main/resources/bubble/node_progress_meter_ticks.json 查看文件

@@ -1,13 +1,13 @@
[
{ "percent": 38,"messageKey":"ansible_deps", "match": "prefix", "pattern":"Building wheel for PyYAML (setup.py): started" },
{ "percent": 41,"messageKey":"config_node", "match": "prefix", "pattern":"PLAY [Configure new bubble node]" },
{ "percent": 42,"messageKey":"nginx_dhparam", "match": "prefix", "pattern":"TASK [nginx : Create a strong dhparam.pem]" },
{ "percent": 55,"messageKey":"nginx_dh_conf", "match": "prefix", "pattern":"TASK [Create dhparam nginx conf]" },
{ "percent": 56,"messageKey":"nginx_certbot", "match": "prefix", "pattern":"TASK [nginx : Init certbot]" },
{ "percent": 58,"messageKey":"bubble_db", "match": "prefix", "pattern":"TASK [bubble : Populate database]" },
{ "percent": 65,"messageKey":"algo_sh", "match": "prefix", "pattern":"TASK [Write install_algo.sh template]" },
{ "percent": 92,"messageKey":"restart_algo", "match": "prefix", "pattern":"TASK [Restart algo monitors]" },
{ "percent": 95,"messageKey":"mitmproxy_set_cert","match": "prefix", "pattern":"TASK [mitmproxy : Set the cert name]" },
{ "percent": 98,"messageKey":"touch_first_setup", "match": "prefix", "pattern":"TASK [finalizer : Touch first-time setup file]" },
{ "percent": 100,"messageKey":"ssh_keys", "match": "prefix", "pattern":"TASK [finalizer : Ensure authorized SSH keys are up-to-date]" }
{ "percent": 29,"messageKey":"ansible_deps", "match": "prefix", "pattern":"Building wheel for PyYAML (setup.py): started" },
{ "percent": 31,"messageKey":"config_node", "match": "prefix", "pattern":"PLAY [Configure new bubble node]" },
{ "percent": 32,"messageKey":"nginx_dhparam", "match": "prefix", "pattern":"TASK [nginx : Create a strong dhparam.pem]" },
{ "percent": 41,"messageKey":"nginx_dh_conf", "match": "prefix", "pattern":"TASK [Create dhparam nginx conf]" },
{ "percent": 42,"messageKey":"nginx_certbot", "match": "prefix", "pattern":"TASK [nginx : Init certbot]" },
{ "percent": 44,"messageKey":"bubble_db", "match": "prefix", "pattern":"TASK [bubble : Populate database]" },
{ "percent": 49,"messageKey":"algo_sh", "match": "prefix", "pattern":"TASK [Write install_algo.sh template]" },
{ "percent": 69,"messageKey":"restart_algo", "match": "prefix", "pattern":"TASK [Restart algo monitors]" },
{ "percent": 72,"messageKey":"mitmproxy_set_cert","match": "prefix", "pattern":"TASK [mitmproxy : Set the cert name]" },
{ "percent": 76,"messageKey":"touch_first_setup", "match": "prefix", "pattern":"TASK [finalizer : Touch first-time setup file]" },
{ "percent": 81,"messageKey":"ssh_keys", "match": "prefix", "pattern":"TASK [finalizer : Ensure authorized SSH keys are up-to-date]" }
]

+ 4
- 5
bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties 查看文件

@@ -359,7 +359,7 @@ meter_tick_running_ansible=Whipping the batter...
# Launch progress meter: install ticks
meter_tick_ansible_deps=Mixing the pie filling...
meter_tick_config_node=Filling the pie...
meter_tick_nginx_dhparam=Gently adding the lattice top crust...
meter_tick_nginx_dhparam=Gently weaving the lattice top crust...
meter_tick_nginx_dh_conf=Glazing the top crust...
meter_tick_nginx_certbot=Checking the temperature...
meter_tick_bubble_db=Putting pie into the oven...
@@ -367,7 +367,7 @@ meter_tick_algo_sh=Baking the pie...
meter_tick_restart_algo=Removing pie from the oven...
meter_tick_mitmproxy_set_cert=Letting the pie cool a bit...
meter_tick_touch_first_setup=Setting the table...
meter_tick_ssh_keys=Hey everybody, the pie is ready!
meter_tick_ssh_keys=Ringing the bell...
#meter_tick_ansible_deps=Installing installer dependencies
#meter_tick_config_node=Configuration installation
#meter_tick_nginx_dhparam=Securing SSL libraries
@@ -404,11 +404,10 @@ meter_unknown_error=An unknown error occurred
title_launch_help_html=Next Steps

message_launch_help_html=<p>Your Bubble will take about 10 minutes to launch and configure itself.</p>
message_launch_help_apps=While you wait for your Bubble to be ready, please install the Bubble app on each of your devices.
message_launch_help_apps=Please install the Bubble app on each of your devices to connect them to your Bubble.
message_launch_success_help_html=<p>Congratulations! Your Bubble is now running.</p>
message_launch_support=<p>Having trouble? Any questions? Check our our <a target="_blank" rel="noopener noreferrer" href="/support">{{messages.link_support}}</a> resources.</p>

message_launch_success_apps=Install the Bubble app on each of your devices and get connected to your Bubble!
message_launch_success_apps=Install the Bubble app on each of your devices to start using your Bubble!

# Network statuses
msg_network_state_created=initialized


+ 1
- 0
bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties 查看文件

@@ -190,6 +190,7 @@ err.name.invalid=Name is invalid
err.name.networkNameAlreadyExists=Name is already in use
err.name.regexFailed=Name must start with a letter and can only contain letters, numbers, hyphens, periods and underscores
err.name.mismatch=Name mismatch
err.node.notReady=Bubble is not ready yet
err.password.required=Password is required
err.password.tooShort=Password must be at least 8 characters
err.password.invalid=Password must contain at least one letter, one number, and one special character


+ 61
- 29
bubble-server/src/main/resources/packer/roles/algo/files/algo_refresh_users.sh 查看文件

@@ -4,7 +4,11 @@
#
LOG=/tmp/bubble.algo_refresh_users.log

ALGO_BASE=/root/ansible/roles/algo/algo
REFRESH_MARKER=${ALGO_BASE}/.refreshing_users

function die {
rm -f ${REFRESH_MARKER}
echo 1>&2 "${1}"
log "${1}"
exit 1
@@ -14,7 +18,6 @@ function log {
echo "$(date): ${1}" >> ${LOG}
}

ALGO_BASE=/root/ansible/roles/algo/algo
if [[ ! -d ${ALGO_BASE} ]] ; then
die "Algo VPN directory ${ALGO_BASE} not found"
fi
@@ -27,32 +30,61 @@ if [[ ! -f "${ALGO_BASE}/config.cfg.hbs" ]] ; then
die "No ${ALGO_BASE}/config.cfg.hbs found"
fi

START_TIME=$(date +%s)
REFRESH_TIMEOUT=300
OK_TO_REFRESH=0
if [[ -f ${REFRESH_MARKER} ]] ; then
log "Refresh marker exists: ${REFRESH_MARKER}, waiting for previous refresh run to finish"
while [[ $(expr $(date +%s) - ${START_TIME}) -lt ${REFRESH_TIMEOUT} ]] ; do
if [[ ! -f ${REFRESH_MARKER} ]] ; then
OK_TO_REFRESH=1
break
fi
sleep 1s
done
if [[ ${OK_TO_REFRESH} -eq 0 ]] ; then
log "Timeout waiting for previous refresh, continuing anyway"
fi
touch ${REFRESH_MARKER}
fi

ALGO_CONFIG="${ALGO_BASE}/config.cfg"
ALGO_CONFIG_SHA="$(sha256sum ${ALGO_CONFIG} | cut -f1 -d' ')"

log "Regenerating algo config..."
java -cp /home/bubble/api/bubble.jar bubble.main.BubbleMain generate-algo-conf --algo-config ${ALGO_BASE}/config.cfg.hbs || die "Error writing algo config.cfg"

log "Updating algo VPN users..."
cd ${ALGO_BASE} && \
python3 -m virtualenv --python="$(command -v python3)" .env \
&& source .env/bin/activate \
&& python3 -m pip install -U pip virtualenv \
&& python3 -m pip install -r requirements.txt \
&& ansible-playbook users.yml --tags update-users --skip-tags debug \
-e "ca_password=$(cat ${CA_PASS_FILE})
provider=local
server=localhost
store_cakey=true
ondemand_cellular=false
ondemand_wifi=false
store_pki=true
dns_adblocking=false
ssh_tunneling=false
endpoint={{ endpoint }}
server_name={{ server_name }}" 2>&1 | tee -a ${LOG} || die "Error running algo users.yml"

# Archive configs in a place that the BackupService can pick them up
log "Sync'ing algo VPN users to bubble..."
CONFIGS_BACKUP=/home/bubble/.BUBBLE_ALGO_CONFIGS.tgz
cd ${ALGO_BASE} && tar czf ${CONFIGS_BACKUP} configs && chgrp bubble ${CONFIGS_BACKUP} && chmod 660 ${CONFIGS_BACKUP} || die "Error backing up algo configs"
cd /home/bubble && rm -rf configs/* && tar xzf ${CONFIGS_BACKUP} && chgrp -R bubble configs && chown -R bubble configs && chmod 500 configs || die "Error unpacking algo configs to bubble home"

log "VPN users successfully sync'd to bubble"
java -cp /home/bubble/api/bubble.jar bubble.main.BubbleMain generate-algo-conf --algo-config ${ALGO_CONFIG}.hbs || die "Error writing algo config.cfg"
NEW_ALGO_CONFIG_SHA="$(sha256sum ${ALGO_CONFIG} | cut -f1 -d' ')"

if [[ ! -z "${ALGO_CONFIG_SHA}" && "${ALGO_CONFIG_SHA}" == "${NEW_ALGO_CONFIG_SHA}" ]] ; then
log "Algo configuration is unchanged, not refreshing: ${ALGO_CONFIG}"

else
log "Updating algo VPN users..."
cd ${ALGO_BASE} && \
python3 -m virtualenv --python="$(command -v python3)" .env \
&& source .env/bin/activate \
&& python3 -m pip install -U pip virtualenv \
&& python3 -m pip install -r requirements.txt \
&& ansible-playbook users.yml --tags update-users --skip-tags debug \
-e "ca_password=$(cat ${CA_PASS_FILE})
provider=local
server=localhost
store_cakey=true
ondemand_cellular=false
ondemand_wifi=false
store_pki=true
dns_adblocking=false
ssh_tunneling=false
endpoint={{ endpoint }}
server_name={{ server_name }}" 2>&1 | tee -a ${LOG} || die "Error running algo users.yml"

# Archive configs in a place that the BackupService can pick them up
log "Sync'ing algo VPN users to bubble..."
CONFIGS_BACKUP=/home/bubble/.BUBBLE_ALGO_CONFIGS.tgz
cd ${ALGO_BASE} && tar czf ${CONFIGS_BACKUP} configs && chgrp bubble ${CONFIGS_BACKUP} && chmod 660 ${CONFIGS_BACKUP} || die "Error backing up algo configs"
cd /home/bubble && rm -rf configs/* && tar xzf ${CONFIGS_BACKUP} && chgrp -R bubble configs && chown -R bubble configs && chmod 500 configs || die "Error unpacking algo configs to bubble home"

log "VPN users successfully sync'd to bubble. Refresh completed in $(expr $(date +%s) - ${START_TIME}) seconds"
fi

rm -f ${REFRESH_MARKER}

+ 1
- 2
bubble-server/src/main/resources/packer/roles/algo/files/algo_refresh_users_monitor.sh 查看文件

@@ -41,9 +41,8 @@ log "Watching marker file..."
while : ; do
if [[ $(stat -c %Y ${BUBBLE_USER_MARKER}) -gt $(stat -c %Y ${ALGO_USER_MARKER}) ]] ; then
touch ${ALGO_USER_MARKER}
sleep 5s
log "Refreshing VPN users..."
/usr/local/bin/algo_refresh_users.sh && log "VPN users successfully refreshed" || log "Error refreshing Algo VPN users"
fi
sleep 10s
sleep 2s
done

+ 2
- 2
bubble-server/src/main/resources/packer/roles/mitmproxy/files/bubble_conn_check.py 查看文件

@@ -223,13 +223,13 @@ def next_layer(next_layer):
check = check_connection(client_addr, server_addr, fqdns, security_level)

if check is None or ('passthru' in check and check['passthru']):
bubble_log('next_layer: enabling passthru for server_addr' + server_addr+', fqdns='+str(fqdns))
bubble_log('next_layer: enabling passthru for server=' + server_addr+', fqdns='+str(fqdns))
bubble_activity_log(client_addr, server_addr, 'tls_passthru', fqdns)
next_layer_replacement = RawTCPLayer(next_layer.ctx, ignore=True)
next_layer.reply.send(next_layer_replacement)

elif 'block' in check and check['block']:
bubble_log('next_layer: enabling block for server_addr' + server_addr+', fqdns='+str(fqdns))
bubble_log('next_layer: enabling block for server=' + server_addr+', fqdns='+str(fqdns))
bubble_activity_log(client_addr, server_addr, 'conn_block', fqdns)
next_layer.__class__ = TlsBlock



+ 2
- 2
bubble-server/src/test/resources/models/tests/auth/device_crud.json 查看文件

@@ -108,8 +108,8 @@
"response": {
"check": [
{"condition": "json.length === 2"},
{"condition": "json[0].getName() === 'root-renamed-device'"},
{"condition": "json[1].getName() === 'user-added-device'"}
{"condition": "_find(json, function (d) { return d.getName() == 'user-added-device'; }) != null"},
{"condition": "_find(json, function (d) { return d.getName() == 'root-renamed-device'; }) != null"}
]
}
},


正在加载...
取消
保存