Windows 11의 인증실패

요즘따라 자꾸 뭔가 문제가 발생한다. 트위터 계정이 탈취당하고(고객센터에서 우린 당신이 계정 주인임을 인정할 수 없다. 라는 일괄적인 통보로 고구마 엔딩), 구글 플레이 스토어에서는 공공요금 청구서에 이름 세글자가 정확하게 적혀있지 않다고 신원인증 거절하고(공공요금 청구서는 이름을 개인정보로 취급하므로 세글자를 찍어주지 않음. 즉 불가능한 방법을 구글에서 요구), 이번엔 하드 증설로 윈도우 새로 설치했다가 정품인증이 안되어 반나절 날려먹었다.

결론은 허무하게 인증되었다.

스크린샷은 남아있지 않지만 발생한 오류코드는 0x803F700F로 메시지 내용은 아래의 노란색 글자와같았다. (출처: MS포럼)

윈도우 11은 붉은화면이 아니라 그냥 제어판에서 노란색 글자가 표기되고 문제 해결을 누르면 아래처럼 처럼 “해결을 완료”하였다면서 “정품 인증할 수 없습니다”라는 역설적인 내용의 화면이 뜨게된다.

이번엔 새로운 하드에 설치를 할 겸 바이오스도 업데이트를 함께 하였는데 정품인증이 안되었다는 메시지가 떠서 이미 오래 전에 겪었던대로 “최근에 이 디바이스의 하드웨어를 변경했습니다.”를 클릭하여 기존 인등되었던 PC를 선택하여 다음을 눌렀다.

하지만 뜨는 메시지는 아래와같았다

이것때문에 거의 네시간 넘게 구글링하고 다시 시도하는것을 반복했는데… 마지막으로 거의 자포자기식으로 MS 계정 장치 페이지에서 현재 사용중인 윈도우를 제외하고 다 지워버렸다.

그 후에도 정품인증이 안되어 다시 “최근에 이 디바이스의 하드웨어를 변경했습니다.”를 클릭하니 DESKTOP-i9는 사라져있고 오래 전 QEMU에서 KVM가속환경에서 인증을 한적 있던것이 DESKTOP-i5와 함께 남아있길레 그거로 선택하여 확인하니까 정품인증이 완료되었다는 메시지가 떴다.

결론은 아래 화면에서 장치이름이 포맷 직전에 사용중이였던 장치와 전혀 다른 장치로 선택해야 인증이 되는 경우가 있다는 것이고 인증이 완료되었어도 디바이스 정보가 실제와 다를 수 있다는것이 이번에 겪으면서 느낀 결론이다. (자포자기 식으로 선택했기때문에 안타깝게도 선택하기 전 장치 이름을 남기지 못했다. 내용은 DESKTOP-렌덤문자, Windows Professional, QEMU였다.)

혹시라도 방금 전 포맷한 장치가 맞는데 선택하여 인증을 하려해도 인증이 안된다면 엉뚱한 이름으로 등록 된 장치가 있을 경우 그걸 선택하여 정품 인증을 진행 해보자.

올해는 더이상 이상한거로 스트레스좀 안받았으면 좋겠다.

그나저나 24H2로 새로 설치해도 내 MS 계정은 홈 폴더의 폴더 레이블이 저따구로 표시되는구나. 대체 왜 내 계정만 저런거냐.

개노답 구글 플레이스토어

저번달 플레이스토어에서 앱이 삭제되었다. 원인은 신원인증을 받지 않았다는 것. 결론부터 적는다면 현재 한달동안 시도한 결과 아직도 통과 못하고있다.

2025-01-18 추가) 주민등록표 등본을 정부24 홈페이지에서 PDF로 출력하여 종이로 출력이나 중요정보 가리지 않고 PDF 원본 그대로 ‘문서 업로드’에 첨부하여 통과된 상태다.

대한민국의 정책때문이라는데 작년 말부터 신원인증을 하기 시작했다. 안내 메일이 딱 한번왔고 자세히 내용 못보고 지나쳐버렸는데 앱이 삭제되었다는 제목으로 어느날 메일이 왔다.

뭐지? 싶어 메일함을 뒤져보고 확인하게되었다. (구글이 정책변경되었음을 알리는 통보를 충분하게 했느냐를 따진다면, 약 반년이나되는 기한동안 신원인증을 받으라는 안내를 딱 한번만 보내고 어느순간 앱이 스토어에서 삭제되었다고 통보를 하는게 맞느냐로 따지고싶다.)

문서 업로드를 할 때 안내에 따르면 신원 인증을 위해 아래와같이 90일 아내 발급 된 청구서나 임대 계약서가 필요하다.

부동산에서 작년 중순 연장계약했으므로 임대 계약서는 불가능. 임대 계약서를 구글링하니 확정일자 발급이 안내되던데 주민센터에서 확정일자를 받으면 온라인에서 출력이 불가능하여 이것또한 문서 출력 불가.

은행 명세서는 명확하게 뭐가 필요한지 모르겠고 구글링해도 명확하게 뭘 의미하는지 알 수 없다. 전기, 수도는 아파트여서 관리사무소에서 각 세대별로 받는것이므로 관리비 청구서는 불가능. (애초 주소가 없고 동과 호수만 표기된다.)

이제 가능한 방법은 내 명의로 되어있는 가스요금 청구서와 신용카드 명세서 두가지 밖에 없다.

13개의 메일 리플된것이 보이는가… 원래 청구서를 모두 이메일 청구서로 받고 있었기때문에 PDF 문서를 업로드했으나 실패. JPG로 저장하여 업로드하였으나 또 실패. 구글링해보니 인쇄하여 사진을 찍어 올려야 한다는 글이 있었다. (왜 PDF 형식을 업로드 허용하는지 모르겠다. 2025-01-18 추가: 주민등록표 등본의 PDF 파일로 통과된 현재 종이로 출력 할 필요가 없음이 확인되었다.)

결국 동내 프린트 카페에서 인쇄하여 사진을 찍어서 올렸으나 또 실패. 언제나 위 스크린샷처럼 네 모서리가 찍혀야하고 번짐이 없어야하며 충분한 조명아래 찍으라고 떴다. 그래서 두세번 LED 조명까지 써가면서 찍어도 실패하였다.

아래는 그렇게 찍은 최종사진. (물론 제출할때는 텍스트를 가리지 않았으며 첨부한 사진은 블로그 업로드를 위해 1920이하로 리사이징 한것이며 원본사이즈 4천픽셀 이미지.)

Continue reading 개노답 구글 플레이스토어

2단계 인증은 필수

1주일 전 트위터 계정이 탈취당하는 일이 발생했다. 결론은 계정주를 확인할 수 없으므로 아무것도 할 수 있는게 없다였다. 거의 일주일동안 회신이 오길 하루이틀씩 기다리다보니 우리나라가 신원인증을 쉽게 할 수 있다는것도 크게 느꼈다.

지난 일주일동안 트위터의 계정 보안을 살펴보니 새로운 장치에서 연결되는것을 막으려면 2단계 인증밖에 답이 없어보였다. 그렇지 않으면 다른 사람이 로그인 가능하고 회원 정보에 접근하여 메일주소 바꾸고 비밀번호 바꾸고 휴대전화 번호를 제거할 수 있고 연결 된 장치또한 클릭 한번으로 모두 해지할 수 있다. 심지어 브라우저에 로그인 된 상태라면 2단계 인증도 메일이나 문자나 비밀번호 인증없이 클릭만으로 해제할 수 있었다.

Continue reading 2단계 인증은 필수

윈도우에서 라즈베리파이 커널 빌드

WSL이나 qemu등을 사용하지 않고 MSYS2에서 라즈베리파이 커널 빌드와 busybox를 initd로 사용하여 부팅가능한 SD카드 만드는 과정을 기록한다. MSYS2에서 만들면 발생하는 문제점으로는 라즈베리파이가 부팅 된 이후 특별히 할 수 있는것이 없다.

WSL을 사용하거나 qemu에서 HAXM 가속으로 리눅스를 부팅해서 작업하는것이 시간도 몇배나 절약되고 자잘한 문제가 덜 발생한다. 예로 윈도우에서 빌드한 툴체인에서 libc를 static 라이브러리로 링크하면 _Unwind_Resume등을 찾을 수 없어서 링크가 불가능하여 라즈베리파이에서 구동되는 컴파일러를 빌드할 수 없는 등 할 수 없는 작업들이 많다. (LDPlayer같은 프로그램을 사용한다면 하이퍼바이저를 사실상 사용할 수 없기때문에 WSL을 사용할 수 없다.)

만약 부팅가능한 SD 카드를 만들고 젠투 리눅스같은 배포본을 설치 할 예정이라면 MSYS2에서도 시도할만하다.

Continue reading 윈도우에서 라즈베리파이 커널 빌드

Qt 6.6.1 MSVC 2022로 빌드

MSVC 2022로 Qt 6.6.1버전 빌드 시 발생하는 오류 리스트

  1. 소스코드 파일 인코딩 오류 (비 유니코드 언어가 영어 (미국)이 아닌경우)
  2. qtwebengine/src/3rdparty/gn/src/gn/variables.cc 텍스트 오류 (1번 항목과 동일한 환경, 577번 라인의 0xA0(NBSP) 캐릭터에서 에러 발생하며 0x20(SPACE)으로 변경하면 해결)
  3. qtwebengine/src/3rdparty/chromium/third_party/webrtc/rtc_base/checks.h LogStreamer의 연산자 오류
  4. gperf 버전이 3.1이상일 경우 오류 발생 ((standard input):1915: warning: junk after %% is ignored 메시지 발생하며 파일이 정상처리 안됨)

크게 네가지 오류가 나타난다. 이 중 1, 2번은 이 글에서 “지역설정” 항목을 참조하여 변경하면 해결 된다. 3번 항목은 vcpkg 프로젝트에서 qtwebengine 패키지의 패치(clang-cl.patch, msvc-template.patch)를 그대로 적용하면 해결된다. 4번은 Qt 5.15.x 버전을 다운받은 후 gnuwin32\bin 경로를 PATH의 맨 앞으로 추가하여 clean & build 하면 해결된다.

만약 시스템 로케일 변경이 귀찮거나 재부팅을 하기에 곤란하다면 아래 소스코드를 빌드 후 실행하여 UTF-8 BOM을 추가하고 환경변수에 “PYTHONUTF8=1″을 추가(프롬프트에서 SET PYTHONUTF8=1 실행)하여 파이선의 파일 인코딩을 UTF-8로 인식하도록 설정한다.

아래 코드는 NBSP문자를 SPACE로 변환 및 확장 아스키 영역의 문자가 있을 경우 UTF-8 BOM을 추가한다.

/*
 * 파일명: CSourceSetUtf8Bom.cpp
 * 빌드명령: cl CSourceSetUtf8Bom.cpp /O2 /std:c++20 /EHsc
 * 실행: CSourceSetUtf8Bom <qt source path>
 * 실행 예: CSourceSetUtf8Bom D:\OpenSource\Qt6.6.1.src
 */

#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>

static void fetch(const std::filesystem::path& source_path, std::size_t& count)
{
    std::cout << count << "\r";
    std::filesystem::directory_iterator it(source_path);

    for (; it != std::filesystem::end(it); it++)
    {
        if (std::filesystem::is_directory(*it))
        {
            fetch(*it, count);
        }
        else
        {
            std::string path = it->path().string();

            if (!path.ends_with(".c") && !path.ends_with(".cc") && !path.ends_with(".cpp") && !path.ends_with(".h"))
            //if (!path.ends_with(".py"))
            {
                continue;
            }

            count++;

            std::basic_ifstream<unsigned char> istream(path);
            std::basic_string<unsigned char> content((std::istreambuf_iterator<unsigned char>(istream)), std::istreambuf_iterator<unsigned char>());

            istream.close();

            if (content.size() >= 3 && content[0] == 0xEF && content[1] == 0xBB && content[2] == 0xBF)
            {
                continue;
            }

            bool extended = std::find_if(content.begin(), content.end(), [](unsigned char c) { return c > 127; }) != content.end();
            if (!extended)
            {
                continue;
            }

            std::cout << count << ", " << it->path().string() << ", " << content.size() << " bytes\n";

            // replace NBSP -> SPACE
            std::replace(content.begin(), content.end(), 0xA0, 0x20);
            std::basic_ofstream<unsigned char> ofstream(path);

            ofstream << static_cast<unsigned char>(0xEF);
            ofstream << static_cast<unsigned char>(0xBB);
            ofstream << static_cast<unsigned char>(0xBF);
            ofstream << content;

            ofstream.close();
        }
    }
}

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        std::cout << argv[0] << " <FOLDER>\n";

        return EXIT_FAILURE;
    }

    std::size_t count = 0;
    std::filesystem::path source_root(argv[1]);

    if (!std::filesystem::is_directory(source_root))
    {
        return EXIT_FAILURE;
    }
    fetch(source_root, count);

    return EXIT_SUCCESS;
}