/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.config.server.controller;

import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.Objects;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.event.DerbyImportEvent;
import com.alibaba.nacos.config.server.service.datasource.DynamicDataSource;
import com.alibaba.nacos.config.server.service.datasource.LocalDataSourceServiceImpl;
import com.alibaba.nacos.config.server.service.dump.DumpService;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.repository.embedded.DatabaseOperate;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.core.utils.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * Manage controllers.
 *
 * @author Nacos
 */
@RestController
@RequestMapping(Constants.OPS_CONTROLLER_PATH)
public class ConfigOpsController {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigOpsController.class);
    
    protected final PersistService persistService;
    
    private final DumpService dumpService;
    
    @Autowired
    public ConfigOpsController(PersistService persistService, DumpService dumpService) {
        this.persistService = persistService;
        this.dumpService = dumpService;
    }
    
    /**
     * Manually trigger dump of a local configuration file.
     */
    @PostMapping(value = "/localCache")
    public String updateLocalCacheFromStore() {
        LOGGER.info("start to dump all data from store.");
        dumpService.dumpAll();
        LOGGER.info("finish to dump all data from store.");
        return HttpServletResponse.SC_OK + "";
    }
    
    @PutMapping(value = "/log")
    public String setLogLevel(@RequestParam String logName, @RequestParam String logLevel) {
        LogUtil.setLogLevel(logName, logLevel);
        return HttpServletResponse.SC_OK + "";
    }
    
    /**
     * // TODO In a future release, the front page should appear operable The interface to the Derby operations query
     * can only run select statements and is a direct query to the native Derby database without any additional logic.
     *
     * @param sql The query
     * @return {@link RestResult}
     */
    @GetMapping(value = "/derby")
    public RestResult<Object> derbyOps(@RequestParam(value = "sql") String sql) {
        String selectSign = "select";
        String limitSign = "ROWS FETCH NEXT";
        String limit = " OFFSET 0 ROWS FETCH NEXT 1000 ROWS ONLY";
        try {
            if (PropertyUtil.isEmbeddedStorage()) {
                LocalDataSourceServiceImpl dataSourceService = (LocalDataSourceServiceImpl) DynamicDataSource
                        .getInstance().getDataSource();
                if (StringUtils.startsWithIgnoreCase(sql, selectSign)) {
                    if (!StringUtils.containsIgnoreCase(sql, limitSign)) {
                        sql += limit;
                    }
                    JdbcTemplate template = dataSourceService.getJdbcTemplate();
                    List<Map<String, Object>> result = template.queryForList(sql);
                    return RestResultUtils.success(result);
                }
                return RestResultUtils.failed("Only query statements are allowed to be executed");
            }
            return RestResultUtils.failed("The current storage mode is not Derby");
        } catch (Exception e) {
            return RestResultUtils.failed(e.getMessage());
        }
    }
    
    /**
     * // TODO the front page should appear operable The external data source is imported into derby.
     *
     * <p>mysqldump --defaults-file="XXX" --host=0.0.0.0 --protocol=tcp --user=XXX --extended-insert=FALSE \
     * --complete-insert=TRUE \ --skip-triggers --no-create-info --skip-column-statistics "{SCHEMA}" "{TABLE_NAME}"
     *
     * @param multipartFile {@link MultipartFile}
     * @return {@link DeferredResult}
     */
    @PostMapping(value = "/data/removal")
    @Secured(action = ActionTypes.WRITE, resource = "nacos/admin")
    public DeferredResult<RestResult<String>> importDerby(@RequestParam(value = "file") MultipartFile multipartFile) {
        DeferredResult<RestResult<String>> response = new DeferredResult<>();
        if (!PropertyUtil.isEmbeddedStorage()) {
            response.setResult(RestResultUtils.failed("Limited to embedded storage mode"));
            return response;
        }
        DatabaseOperate databaseOperate = ApplicationUtils.getBean(DatabaseOperate.class);
        WebUtils.onFileUpload(multipartFile, file -> {
            NotifyCenter.publishEvent(new DerbyImportEvent(false));
            databaseOperate.dataImport(file).whenComplete((result, ex) -> {
                NotifyCenter.publishEvent(new DerbyImportEvent(true));
                if (Objects.nonNull(ex)) {
                    response.setResult(RestResultUtils.failed(ex.getMessage()));
                    return;
                }
                response.setResult(result);
            });
        }, response);
        return response;
    }
    
}

@@ -4010,16 +4010,82 @@
 derby%22)%0A
+    @Secured(action = ActionTypes.READ, resource = %22nacos/admin%22)%0A
     publ

fix derbyOps interface security problem (#4517)