using System.Diagnostics; using Microsoft.AspNetCore.Mvc; using System.Text.Json; using System.Security.Cryptography; using System.Text; using AcaMate.Common.Data; using AcaMate.Common.Models; using AcaMate.Common.Token; using AcaMate.V1.Models; using AcaMate.V1.Services; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Version = AcaMate.V1.Models.Version; namespace AcaMate.V1.Controllers; [ApiController] [Route("/api/v1/in/app")] [ApiExplorerSettings(GroupName = "공통")] public class AppController : ControllerBase { private readonly AppDbContext _dbContext; private readonly ILogger _logger; private readonly IRepositoryService _repositoryService; private readonly JwtTokenService _jwtTokenService; public AppController(AppDbContext dbContext, ILogger logger, IRepositoryService repositoryService, JwtTokenService jwtTokenService) { _dbContext = dbContext; _logger = logger; _repositoryService = repositoryService; _jwtTokenService = jwtTokenService; } // 이 키값의 제한 시간은 24h이다 [HttpGet] [CustomOperation("헤더 정보 생성", "헤더에 접근하기 위한 키 값 받아오기", "시스템")] public async Task GetHeaderValue(string type, string specific, string project) { if (string.IsNullOrEmpty(specific) || string.IsNullOrEmpty(type) || string.IsNullOrEmpty(project)) return BadRequest(APIResponse.InvalidInputError()); if (!ModelState.IsValid) return BadRequest(APIResponse.InvalidInputError()); string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(AppController), "GetHeaderValue"); bool valid = false; switch (type) { case "I": if (project == "me.myds.ipstein.acamate.AcaMate") valid = true; break; case "A": break; case "W": break; default: return BadRequest(APIResponse.InvalidInputError($"[{summary}], 타입 에러")); break; } if (valid) { var apiHeader = await _dbContext.APIHeader.FirstOrDefaultAsync(h => h.specific_id == specific); string nowTime = DateTime.Now.ToString("o"); string combineText = $"{project}_{nowTime}_{specific}"; string headerValue = KeyGenerator(combineText); if (apiHeader != null) { if (DateTime.Now - apiHeader.connect_date > TimeSpan.FromHours(24)) { _logger.LogInformation($"[{summary}] : 해당 키 유효기간 경과"); apiHeader.h_value = headerValue; apiHeader.connect_date = DateTime.Now; if (await _repositoryService.SaveData(apiHeader)) { string msg = "정상 - 로그 저장 실패"; var logProject = new LogProject { create_date = DateTime.Now , log = $"[{summary}] : 해당 키 유효시간 만료로 인한 새 키 부여" }; if (await _repositoryService.SaveData(logProject)) msg = "정상"; return Ok(APIResponse.Send("001", msg, new { header = headerValue })); } else { // 저장이 안된거니 서버 오류 return StatusCode(500, APIResponse.InternalSeverError()); } } else { // 유효기간 만료 이상 없이 다 잘 됨 return Ok(APIResponse.Send("000", "정상", new { header = apiHeader.h_value })); } } else { _logger.LogInformation($"[{summary}] : 저장 된게 없음"); var newHeader = new APIHeader { h_key = type == "I" ? "iOS_AM_Connect_Key" : (type == "A" ? "And_AM_Connect_Key" : (type == "W" ? "Web_AM_Connect_Key": throw new Exception("ERROR"))), h_value = headerValue, connect_date = DateTime.Now, specific_id = specific }; if (await _repositoryService.SaveData(newHeader)) { string msg = "정상 - 로그 저장 실패"; var logProject = new LogProject { create_date = DateTime.Now , log = $"[{summary}] : 새로운 등록으로 인한 새 키 부여" }; // 이거 로그 저장 안되는거 확인! _logger.LogInformation($"[{summary}] : {logProject.log}"); if (await _repositoryService.SaveData(logProject)) msg = "정상"; return Ok(APIResponse.Send("001", msg, new { header = headerValue })); } else { // 저장이 안된거니 서버 오류 return StatusCode(500, APIResponse.InternalSeverError()); } } } return BadRequest(APIResponse.InvalidInputError()); // return Ok(APIResponse.Send("000", "정상", Empty)); } catch (Exception ex) { _logger.LogError($"[{summary}] : {ex.Message}"); return StatusCode(500, APIResponse.UnknownError(ex.Message)); } } // 스웨거는 퍼블릭으로 선언된걸 죄다 API로 인식하는 경향이 있음 // 방법은 private 같이 접근 제한자를 변경하거나 [NonAction]을 붙여주면 됨 [NonAction] private string KeyGenerator(string combineText) { using (SHA256 sha256 = SHA256.Create()) { byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(combineText)); return BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLowerInvariant(); } } [HttpGet("version")] [CustomOperation("앱 버전 확인","앱 버전을 확인해서 업데이트 여부 판단", "시스템")] public async Task GetVersionData(string type) { if (string.IsNullOrEmpty(type)) { return BadRequest(APIResponse.InvalidInputError()); } try { var version = await _dbContext.Version.FirstOrDefaultAsync(v => v.os_type == (type == "I" ? "VO01" : "VO02")); if (version == null) { return NotFound(APIResponse.NotFoundError()); } var response = new APIResponseStatus { status = new Status() { code = "000", message = "정상" }, data = new Version() { os_type = (version.os_type == "VO01" ? "I" : (version.os_type == "VO02" ? "A" : "W")), final_ver = version.final_ver, force_ver = version.force_ver, dev_ver = version.dev_ver, choice_update_yn = version.choice_update_yn } }; string jsonString = JsonSerializer.Serialize(response); // return Ok(jsonString); return Ok(response.JsonToString()); } catch (Exception ex) { Console.WriteLine($"{ex.Message}\n{ex.StackTrace}"); return StatusCode(500, APIResponse.UnknownError()); } } [HttpGet("auth")] [CustomOperation("서버 접근 권한 확인", "서버 기능을 사용하기 위한 접근에 대해 권한 확인", "시스템")] public async Task AuthProgram([FromBody] AuthKey keys) { string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(AppController), "AuthProgram"); } catch (Exception ex) { _logger.LogError($"[{summary}] : {ex.Message}"); return StatusCode(500, APIResponse.UnknownError(ex.Message)); } return Ok(APIResponse.Send("000", "OK", Empty)); } [HttpGet("retryAccess")] [CustomOperation("엑세스 토큰 재발급", "액세스 토큰 재발급 동작 수행", "시스템")] public async Task RetryAccessToken(string refresh) { string summary = String.Empty; try { summary = _repositoryService.ReadSummary(typeof(AppController), "AuthProgram"); var refreshToken = await _dbContext.RefreshTokens .FirstOrDefaultAsync(t => t.refresh_token == refresh); if (refreshToken == null) throw new TokenException($"[{summary}] : 리프레시 토큰의 문제"); if (refreshToken.revoke_Date < DateTime.Now) throw new TokenException($"[{summary}] : 리프레시 토큰 만료"); if (refreshToken.expire_date < DateTime.Now) throw new TokenException($"[{summary}] : 리프레시 토큰 폐기"); string access = _jwtTokenService.GenerateJwtToken(refreshToken.uid); return Ok(APIResponse.Send("000", $"[{summary}], 토큰 생성 완료", new { access = access })); } catch (TokenException ex) { _logger.LogError($"[{summary}] : {ex.Message}"); return Ok(APIResponse.InvalidInputError(ex.Message)); } catch (Exception ex) { _logger.LogError($"[{summary}] : {ex.Message}"); return StatusCode(500, APIResponse.UnknownError(ex.Message)); } } }